https://docs.basex.org/api.php?action=feedcontributions&user=Andy+Bunce&feedformat=atomBaseX Documentation - User contributions [en]2024-03-28T17:55:30ZUser contributionsMediaWiki 1.34.0https://docs.basex.org/index.php?title=Command-Line_Options&diff=16921Command-Line Options2024-01-20T22:39:53Z<p>Andy Bunce: Q in Expanded QName</p>
<hr />
<div>This article is part of the [[Getting Started]] Guide.<br />
Each BaseX [[Startup]] mode has one or more command-line options, which are described in this article.<br />
<br />
Command-line options can be specified multiple times. Please note that all options will be evaluated in the given order. The standard input can be parsed by specifying a single dash ({{Code|-}}) as an argument.<br />
<br />
{{Announce|Updated with Version 11}}: The Clark notation was replaced with the [[XQuery 3.0#Expanded QNames|Expanded QNames]] notation.<br />
<br />
=Standalone=<br />
<br />
{{Announce|Added with Version 11:}} {{Code|-C}}, {{Code|-Q}}, {{Code|-W}}<br />
<br />
The following options are available for the standalone [[Command-Line Client]]:<br />
<br />
<pre><br />
$ basex -h<br />
BaseX [Standalone]<br />
Usage: basex [-bcdiIoqrRstuvVwxz] [input]<br />
[input] XQuery or command file, or query string<br />
-b<args> Bind external query variables<br />
-c<input> Execute commands from file or string<br />
-C<file> Execute command script file<br />
-d Toggle debugging output<br />
-i<input> Bind file or database to context<br />
-I<input> Bind input string to context<br />
-o<path> Write output to local file<br />
-q<expr> Execute XQuery expression<br />
-Q<file> Execute XQuery file<br />
-r<num> Run query multiple times<br />
-R Toggle query execution<br />
-s<args> Set serialization parameters<br />
-t[path] Run tests in file or directory<br />
-u Toggle updates in original files<br />
-v Toggle output of progress info<br />
-V Toggle detailed query output<br />
-w Toggle whitespace stripping<br />
-W Enable indentation with whitespaces<br />
-x Toggle output of query plan<br />
-z Toggle output of query result<br />
</pre><br />
<br />
Further details are listed in the following table. If an equivalent database option exists (which can be specified via the {{Command|SET}} command), it is listed as well.<br />
For the examples to work, it might be necessary to escape some characters depending on your operating system.<br />
<br />
{| class="wikitable"<br />
|- valign="top"<br />
! width='120' | Flag<br />
! width="40%" | Description<br />
! Option<br />
! Default<br />
! Examples<br />
|- valign="top"<br />
| {{Code|[input]}}<br />
|Evaluates the specified input:<br />
* The input string may point to an existing file. If the file suffix is {{Code|.bxs}}, the file contents will be executed as [[Commands#Basics|Command Script]]; any other file content will be evaluated as XQuery expression.<br />
* Otherwise, the input string itself is evaluated as XQuery expression.<br />
|<br />
|<br />
|• {{Code|"doc('X')//head"}}<br/>• {{Code|query.xq}}<br/>• {{Code|commands.bxs}}<br/><br />
|- valign="top"<br />
| {{Code|-b&lt;args&gt;}}<br />
| Binds external variables to XQuery expressions. This flag may be specified multiple times. Variables names and their values are delimited by equality signs (<code>=</code>). The names may be optionally prefixed with dollar signs. If a variable uses a namespace different from the default namespace, it can be specified with the [[XQuery 3.0#Expanded QNames|Expanded QNames]] notation.<br />
| {{Option|BINDINGS}}<br />
|<br />
|• <code>-bv=example "declare variable $v external; $v"</code><br/>• <code>-bQ{URL}ln=value<br/>"declare namespace ns='URL'; declare variable $ns:ln external; $ns:ln"</code><br />
|- valign="top"<br />
| {{Code|-c&lt;input&gt;}}<br />
| Executes [[commands]]. If the specified input is a valid URI or file reference, this file is evaluated as [[Commands#Command_Scripts|Command Script]].<br />
|<br />
|<br />
|• {{Code|-c list}}<br/>• {{Code|-ccommands.txt}}<br/>• {{Code|-c"<info/>"}}<br />
|- valign="top"<br />
| {{Code|-C&lt;file&gt;}}<br />
| Evaluates the contents of the specified file as [[Commands#Command_Scripts|Command Script]].<br />
|<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-d}}<br />
| Toggles the debugging mode. Debugging information is output to ''standard error''.<br />
| {{Option|DEBUG}}<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-i&lt;input&gt;}}<br />
| Opens the specified XML file, directory with XML files, or database. The opened input can then be processed by a command or XQuery expression.<br />
|<br />
|<br />
| {{Code|-iitems.xml "//item"}}<br />
|- valign="top"<br />
| {{Code|-I&lt;input&gt;}}<br />
| Assigns an input string as item of type {{Code|xs:untypedAtomic}} to the query context.<br />
|<br />
|<br />
| {{Code|-I "Hello Universe" -q "."}}<br />
|- valign="top"<br />
| {{Code|-o&lt;path&gt;}}<br />
| All command and query output is written to the specified file.<br />
|<br />
|<br />
| {{Code|-o output.txt}}<br />
|- valign="top"<br />
| {{Code|-q&lt;expr&gt;}}<br />
| Evaluates the specified string as XQuery expression.<br />
|<br />
|<br />
| {{Code|-q"doc('input')//head"}}<br />
|- valign="top"<br />
| {{Code|-Q&lt;file&gt;}}<br />
| Evaluates the contents of the specified file as XQuery expression.<br />
|<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-r&lt;num&gt;}}<br />
| Specifies how often a specified query will be evaluated.<br />
| {{Option|RUNS}}<br />
| <code>1</code><br />
| {{Code|-V -r10 "1"}}<br />
|- valign="top"<br />
| {{Code|-R}}<br />
| Specifies if a query will be evaluated or parsed and compiled only.<br />
| {{Option|RUNQUERY}}<br />
| <code>true</code><br />
| {{Code|-V -R "1"}}<br />
|- valign="top"<br />
| {{Code|-s&lt;args&gt;}}<br />
| Specifies parameters for serializing XQuery results; see [[Serialization]] for more details. This flag may be specified multiple times. Key and values are separated by the equality sign (<code>=</code>).<br />
| {{Option|SERIALIZER}}<br />
|<br />
| <code>-smethod=text</code><br />
|- valign="top"<br />
| {{Code|-t[path]}}<br />
| Runs all [[Unit Module|Unit tests]] in the specified file or directory.<br />
|<br />
|<br />
| -t project/tests<br />
|- valign="top"<br />
| {{Code|-u}}<br />
| Propagates updates on input files back to disk.<br />
| {{Option|WRITEBACK}}<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-v}}<br />
| Toggles the output of process and timing information.<br />
|<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-V}}<br />
| Prints detailed query information to the ''standard output'', including details on the compilation and profiling steps.<br />
| {{Option|QUERYINFO}}<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-w}}<br />
| Toggles whitespace stripping of XML text nodes. By default, whitespaces will be preserved.<br />
| {{Option|STRIPWS}}<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-W}}<br />
| Enables indentation with whitespace. By default, query results will not be indented.<br />
| {{Option|SERIALIZER}}<br />
| <code>indent=no</code><br />
|<br />
|- valign="top"<br />
| {{Code|-x}}<br />
| Toggles the output of the query execution plan, formatted as XML.<br />
| {{Option|XMLPLAN}}<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-z}}<br />
| Turns the serialization of XQuery results on/off. This flag is useful if the query is profiled or analyzed.<br />
| {{Option|SERIALIZE}}<br />
| <code>true</code><br />
|<br />
|}<br />
<br />
=GUI=<br />
<br />
The following options are available for the standalone [[GUI|Graphical User Interface]]:<br />
<br />
<pre><br />
$ basexgui -h<br />
BaseX [GUI]<br />
Usage: basexgui [-d] [files]<br />
[files] Open specified files<br />
-d Enable debugging<br />
</pre><br />
<br />
You can pass one or more files as parameters. If an XML document is specified, a database instance can be created from this file. Other files are opened in the editor.<br />
<br />
=Server=<br />
<br />
{{Announce|Added with Version 11:}} {{Code|-C}}<br />
<br />
The following options are available for the [[Database Server]]:<br />
<br />
<pre><br />
$ basexserver -h<br />
BaseX [Server]<br />
Usage: basexserver [-cdnpSz] [stop]<br />
stop Stop running server<br />
-c<input> Execute commands from file or string<br />
-C<file> Execute command script file<br />
-d Enable debugging output<br />
-n<name> Set host the server is bound to<br />
-p<port> Set server port<br />
-S Start as service<br />
-z Suppress logging<br />
</pre><br />
<br />
Details on all options are listed in the following table (equivalent database options are shown in the table as well).<br />
For the examples to work, it might be necessary to escape some characters depending on your operating system.<br />
<br />
{| class="wikitable"<br />
|- valign="top"<br />
! width='120' | Flag<br />
! width="40%" | Description<br />
! Option<br />
! Default<br />
! Examples<br />
|- valign="top"<br />
| {{Code|stop}}<br />
| Stops a local database server instance and quits.<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-c&lt;input&gt;}}<br />
| Executes [[commands]]. If the specified input is a valid URI or file reference, this file is evaluated as [[Commands#Command_Scripts|Command Script]].<br />
|<br />
|<br />
| {{Code|-c"open database;info"}}<br />
|- valign="top"<br />
| {{Code|-C&lt;file&gt;}}<br />
| Evaluates the contents of the specified file as [[Commands#Command_Scripts|Command Script]].<br />
|<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-d}}<br />
| Enables debugging output. Debugging information is output to ''standard error''.<br />
| {{Option|DEBUG}}<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-n&lt;name&gt;}}<br />
| Specifies the host the server will be bound to.<br />
| {{Option|SERVERHOST}}<br />
|<br />
| {{Code|-p127.0.0.1}}<br />
|- valign="top"<br />
| {{Code|-p&lt;port&gt;}}<br />
| Specifies the port on which the server will be addressable.<br />
| {{Option|SERVERPORT}}<br />
| {{Code|1984}}<br />
| {{Code|-p9999}}<br />
|- valign="top"<br />
| {{Code|-S}}<br />
| Starts the server as service (i.e., in the background). Use [[YAJSW]], or start BaseX as an ordinary background process to get more options.<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-z}}<br />
| Prevents the generation of [[Logging|log files]].<br />
| {{Option|LOG}}<br />
| <code>true</code><br />
|<br />
|}<br />
<br />
Multiple {{Code|-c}} and {{Code|-i}} flags can be specified. All other options will be set before any other operation takes place. The specified inputs, query files, queries and commands will be subsequently evaluated after that in the given order. The standard input can be parsed by specifying a single dash ({{Code|-}}) as argument.<br />
<br />
=Client=<br />
<br />
{{Announce|Added with Version 11:}} {{Code|-C}}, {{Code|-Q}}, {{Code|-W}}<br />
<br />
If the [[Database Server|Database Client]] is launched, you will be requested for a username and password.<br />
<br />
<pre><br />
$ basexclient -h<br />
BaseX [Client]<br />
Usage: basexclient [-bcdiInopPqrRsUvVwxz] [input]<br />
[input] XQuery or command file, or query string<br />
-b<args> Bind external query variables<br />
-c<input> Execute commands from file or string<br />
-C<file> Execute command script file<br />
-d Toggle debugging output<br />
-i<input> Bind file or database to context<br />
-I<input> Bind input string to context<br />
-n<name> Set server (host) name<br />
-o<path> Write output to local file<br />
-p<port> Set server port<br />
-P<pass> Specify user password<br />
-q<expr> Execute XQuery expression<br />
-Q<file> Execute XQuery file<br />
-r<num> Run query multiple times<br />
-R Toggle query execution<br />
-s<args> Set serialization parameters<br />
-U<name> Specify username<br />
-v Toggle output of progress info<br />
-V Toggle detailed query output<br />
-w Toggle whitespace stripping<br />
-W Enable indentation with whitespaces<br />
-x Toggle output of query plan<br />
-z Toggle output of query result<br />
</pre><br />
<br />
See the following table for details (equivalent database options are shown in the table as well).<br />
For the examples to work, it might be necessary to escape some characters, depending on your operating system.<br />
<br />
{| class="wikitable"<br />
|- valign="top"<br />
! width='120' | Flag<br />
! width="40%" | Description<br />
! Option<br />
! Default<br />
! Examples<br />
|- valign="top"<br />
| {{Code|[input]}}<br />
|Evaluates the specified input:<br />
* The input string may point to an existing file. If the file suffix is {{Code|.bxs}}, the file contents will be evaluated as [[Commands#Basics|Command Script]]; any other file content will be evaluated as XQuery expression.<br />
* Otherwise, the input string itself is evaluated as XQuery expression.<br />
|<br />
|<br />
|• {{Code|"doc('X')//head"}}<br/>• {{Code|query.xq}}<br/>• {{Code|commands.bxs}}<br/><br />
|- valign="top"<br />
| {{Code|-b&lt;args&gt;}}<br />
| Binds external variables to XQuery expressions. This flag may be specified multiple times. Variables names and their values are delimited by equality signs (<code>=</code>). The names may be optionally prefixed with dollar signs. If a variable uses a namespace different from the default namespace, it can be specified with the [[XQuery 3.0#Expanded QNames|Expanded QNames]] notation.<br />
| {{Option|BINDINGS}}<br />
|<br />
|• <code>-b$v=example "declare variable $v external; $v"</code><br/>• <code>-bQ{URL}ln=value<br/>"declare namespace ns='URL'; declare variable $ns:ln external; $ns:ln"</code><br />
|- valign="top"<br />
| {{Code|-c&lt;input&gt;}}<br />
| Executes [[commands]]. If the specified input is a valid URI or file reference, its content will be executed instead. Empty lines and lines starting with the number sign {{Code|#}} will be ignored.<br />
|<br />
|<br />
|• {{Code|-c list}}<br/>• {{Code|-ccommands.txt}}<br/>• {{Code|-c"<info/>"}}<br />
|- valign="top"<br />
| {{Code|-C&lt;file&gt;}}<br />
| Evaluates the contents of the specified file as [[Commands#Command_Scripts|Command Script]].<br />
|<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-d}}<br />
| Toggles the debugging mode. Debugging information is output to ''standard error''.<br />
| {{Option|DEBUG}}<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-i&lt;input&gt;}}<br />
| Opens the specified XML file, directory with XML files, or database. The opened input can then be processed by a command or XQuery expression.<br />
|<br />
|<br />
| {{Code|-iitems.xml "//item"}}<br />
|- valign="top"<br />
| {{Code|-I&lt;input&gt;}}<br />
| Assigns an input string as item of type {{Code|xs:untypedAtomic}} to the query context.<br />
|<br />
|<br />
| {{Code|-I "Hello Universe" -q "."}}<br />
|- valign="top"<br />
| {{Code|-n&lt;name&gt;}}<br />
| Specifies the host name on which the server is running.<br />
| {{Option|HOST}}<br />
| {{Code|localhost}}<br />
| {{Code|-nserver.basex.org}}<br />
|- valign="top"<br />
| {{Code|-o&lt;path&gt;}}<br />
| All command and query output is written to the specified file.<br />
|<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-p&lt;port&gt;}}<br />
| Specifies the port on which the server is running.<br />
| {{Option|PORT}}<br />
| {{Code|1984}}<br />
| {{Code|-p9999}}<br />
|- valign="top"<br />
| {{Code|-P&lt;pass&gt;}}<br />
| Specifies the user password. If this flag is omitted, the password will be requested on command line. ''Warning'': When the password is supplied with this flag, it may end up in logs or the bash history.<br />
| {{Option|PASSWORD}}<br />
|<br />
| {{Code|-Uadmin -P...}}<br />
|- valign="top"<br />
| {{Code|-q&lt;expr&gt;}}<br />
| Executes the specified string as XQuery expression.<br />
|<br />
| {{Code|-q"1+2"}}<br />
|- valign="top"<br />
| {{Code|-Q&lt;file&gt;}}<br />
| Evaluates the contents of the specified file as XQuery expression.<br />
|<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-r&lt;num&gt;}}<br />
| Specifies how often a specified query will be evaluated.<br />
| {{Option|RUNS}}<br />
| <code>1</code><br />
| {{Code|-V -r10 "1"}}<br />
|- valign="top"<br />
| {{Code|-R}}<br />
| Specifies if a query will be executed or parsed only.<br />
| {{Option|RUNQUERY}}<br />
| <code>true</code><br />
| {{Code|-V -R "1"}}<br />
|- valign="top"<br />
| {{Code|-s&lt;args&gt;}}<br />
| Specifies parameters for serializing XQuery results; see [[Serialization]] for more details. This flag may be specified multiple times. Key and values are separated by the equality sign (<code>=</code>).<br />
| {{Option|SERIALIZER}}<br />
|<br />
| <code>-smethod=text</code><br />
|- valign="top"<br />
| {{Code|-U&lt;name&gt;}}<br />
| Specifies the username. If this flag is omitted, the username will be requested on command line.<br />
| {{Option|USER}}<br />
|<br />
| {{Code|-Uadmin}}<br />
|- valign="top"<br />
| {{Code|-v}}<br />
| Prints process and timing information to the ''standard output''.<br />
|<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-V}}<br />
| Prints detailed query information to the ''standard output'', including details on the compilation and profiling steps.<br />
| {{Option|QUERYINFO}}<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-w}}<br />
| Toggles whitespace stripping of XML text nodes. By default, whitespaces will be preserved.<br />
| {{Option|STRIPWS}}<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-W}}<br />
| Enables indentation with whitespace. By default, query results will not be indented.<br />
| {{Option|SERIALIZER}}<br />
| <code>indent=no</code><br />
|<br />
|- valign="top"<br />
| {{Code|-x}}<br />
| Toggles the output of the query execution plan, formatted as XML.<br />
| {{Option|XMLPLAN}}<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-z}}<br />
| Turns the serialization of XQuery results on/off. This flag is useful if the query is profiled or analyzed.<br />
| {{Option|SERIALIZE}}<br />
| <code>true</code><br />
|<br />
|}<br />
<br />
=HTTP Server=<br />
<br />
{{Announce|Added with Version 11:}} {{Code|-C}}<br />
<br />
The following options are available for the [[Web Application|HTTP Server]]:<br />
<br />
<pre><br />
$ basexhttp -h<br />
BaseX [HTTP]<br />
Usage: basexhttp [-cdhlnpsSUz] [stop]<br />
stop Stop running server<br />
-c<input> Execute commands from file or string<br />
-C<file> Execute command script file<br />
-d Enable debugging output<br />
-g Enable GZIP support<br />
-h<port> Set port of HTTP server<br />
-l Start in local mode<br />
-n<name> Set host name of database server<br />
-p<port> Set port of database server<br />
-s<port> Specify port to stop HTTP server<br />
-S Start as service<br />
-U<name> Specify username<br />
-z Suppress logging<br />
</pre><br />
<br />
The meaning of all options is listed in the following table (equivalent database options are shown in the table as well).<br />
For the examples to work, it might be necessary to escape some characters depending on your Operating System.<br />
<br />
{| class="wikitable"<br />
|- valign="top"<br />
! width='120' | Flag<br />
! width="40%" | Description<br />
! Option<br />
! Default<br />
! Examples<br />
|- valign="top"<br />
| {{Code|stop}}<br />
| Stops a local HTTP server and quits. The database server will be stopped as well, unless {{Code|-l}} is specified.<br />
| <code>pom.xml</code><br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-c&lt;input&gt;}}<br />
| Executes [[commands]]. If the specified input is a valid URI or file reference, this file is evaluated as [[Commands#Command_Scripts|Command Script]].<br />
|<br />
|<br />
| {{Code|-c"open database"}}<br />
|- valign="top"<br />
| {{Code|-C&lt;file&gt;}}<br />
| Evaluates the contents of the specified file as [[Commands#Command_Scripts|Command Script]].<br />
|<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-e}}<br />
| Enables debugging output. Debugging information is output to ''standard error''.<br />
| {{Option|DEBUG}}<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-g}}<br />
| Enables GZIP support in Jetty.<br />
| {{Option|GZIP}}<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-h&lt;port&gt;}}<br />
| Specifies the port on which the HTTP server will be addressable.<br />
| <code>jetty.xml</code><br />
| {{Code|8080}}<br />
| {{Code|-h9999}}<br />
|- valign="top"<br />
| {{Code|-l}}<br />
| Starts the server in ''local mode'', and executes all commands in the embedded database context.<br />
| {{Option|HTTPLOCAL}}<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-n&lt;name&gt;}}<br />
| Specifies the host name on which the server is running.<br />
| {{Option|HOST}}<br />
| {{Code|localhost}}<br />
| {{Code|-nserver.basex.org}}<br />
|- valign="top"<br />
| {{Code|-p&lt;port&gt;}}<br />
| Specifies the port on which the database server will be addressable.<br />
| {{Option|SERVERPORT}}<br />
| {{Code|1984}}<br />
| {{Code|-p9998}}<br />
|- valign="top"<br />
| {{Code|-s&lt;port&gt;}}<br />
| Specifies the port that will be used to stop the HTTP server.<br />
| {{Option|STOPPORT}} or<br/><code>pom.xml</code><br />
| <code>8081</code><br />
|<br />
|- valign="top"<br />
| {{Code|-S}}<br />
| Starts the server as service (i.e., in the background). Use [[YAJSW]], or start BaseX as an ordinary background process to get more options.<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-U&lt;name&gt;}}<br />
| Specifies a username, which will be used by the HTTP services for opening a new session.<br />
| {{Option|USER}}<br />
|<br />
| {{Code|-Uadmin}}<br />
|- valign="top"<br />
| {{Code|-z}}<br />
| Prevents the generation of [[Logging|log files]].<br />
| {{Option|LOG}}<br />
|<br />
|}<br />
<br />
=Changelog=<br />
<br />
;Version 11.0<br />
* Added: {{Code|-C}} (standalone, server, client, HTTP server).<br />
* Added: {{Code|-Q}}, {{Code|-W}} (standalone, client).<br />
* Updated: The Clark notation was replaced with the [[XQuery 3.0#Expanded QNames|Expanded QNames]] notation.<br />
<br />
;Version 10.0<br />
* Updated: Whitespaces are now preserved by default (see {{Option|STRIPWS}} for more details).<br />
<br />
;Version 9.0<br />
* Added: BaseXHTTP, command-line option {{Code|-c}}.<br />
* Updated: BaseXHTTP, command-line option {{Code|-c}}, additionally accepts valid URLs and file references.<br />
<br />
;Version 8.2<br />
* Removed: Event ports, {{Code|-e}}.<br />
<br />
;Version 8.1<br />
* Added: Bind input strings to the query context with {{Code|-I}}.<br />
<br />
;Version 8.0<br />
* Removed: Command-line option <code>-L</code> (results will now be automatically separated by newlines).<br />
<br />
;Version 7.9<br />
* Added: Runs tests in file or directory with {{Code|-t}}.<br />
* Removed: interactive server mode.<br />
<br />
;Version 7.8<br />
* Added: Specify if a query will be executed or parsed only with {{Code|-R}}.<br />
<br />
;Version 7.7<br />
* Added: Bind host to the [[#BaseX Server|BaseX Server]] with {{Code|-n}}.<br />
<br />
;Version 7.5<br />
* Added: detection of [[Commands#Basics|Command Scripts]].<br />
* Removed: HTTP server flags {{Code|-R}}, {{Code|-W}}, and {{Code|-X}}.<br />
<br />
; Version 7.3:<br />
* Updated: all options are now evaluated in the given order.<br />
* Updated: Create main-memory representations for specified sources with {{Code|-i}}.<br />
* Updated: Options {{Code|-C}}/{{Code|-c}} and {{Code|-q}}/{{Code|[input]}} merged.<br />
* Updated: Option {{Code|-L}} also separates serialized items with newlines (instead of spaces).<br />
<br />
; Version 7.2:<br />
* Added: RESTXQ Service<br />
<br />
; Version 7.1.1:<br />
* Added: Options {{Code|-C}} and {{Code|-L}} in standalone and client mode.<br />
<br />
; Version 7.1:<br />
* Updated: Multiple query files and {{Code|-c}}/{{Code|-i}}/{{Code|-q}} flags can be specified.</div>Andy Buncehttps://docs.basex.org/index.php?title=Command-Line_Options&diff=16920Command-Line Options2024-01-20T22:38:11Z<p>Andy Bunce: Q in Expanded QName</p>
<hr />
<div>This article is part of the [[Getting Started]] Guide.<br />
Each BaseX [[Startup]] mode has one or more command-line options, which are described in this article.<br />
<br />
Command-line options can be specified multiple times. Please note that all options will be evaluated in the given order. The standard input can be parsed by specifying a single dash ({{Code|-}}) as an argument.<br />
<br />
{{Announce|Updated with Version 11}}: The Clark notation was replaced with the [[XQuery 3.0#Expanded QNames|Expanded QNames]] notation.<br />
<br />
=Standalone=<br />
<br />
{{Announce|Added with Version 11:}} {{Code|-C}}, {{Code|-Q}}, {{Code|-W}}<br />
<br />
The following options are available for the standalone [[Command-Line Client]]:<br />
<br />
<pre><br />
$ basex -h<br />
BaseX [Standalone]<br />
Usage: basex [-bcdiIoqrRstuvVwxz] [input]<br />
[input] XQuery or command file, or query string<br />
-b<args> Bind external query variables<br />
-c<input> Execute commands from file or string<br />
-C<file> Execute command script file<br />
-d Toggle debugging output<br />
-i<input> Bind file or database to context<br />
-I<input> Bind input string to context<br />
-o<path> Write output to local file<br />
-q<expr> Execute XQuery expression<br />
-Q<file> Execute XQuery file<br />
-r<num> Run query multiple times<br />
-R Toggle query execution<br />
-s<args> Set serialization parameters<br />
-t[path] Run tests in file or directory<br />
-u Toggle updates in original files<br />
-v Toggle output of progress info<br />
-V Toggle detailed query output<br />
-w Toggle whitespace stripping<br />
-W Enable indentation with whitespaces<br />
-x Toggle output of query plan<br />
-z Toggle output of query result<br />
</pre><br />
<br />
Further details are listed in the following table. If an equivalent database option exists (which can be specified via the {{Command|SET}} command), it is listed as well.<br />
For the examples to work, it might be necessary to escape some characters depending on your operating system.<br />
<br />
{| class="wikitable"<br />
|- valign="top"<br />
! width='120' | Flag<br />
! width="40%" | Description<br />
! Option<br />
! Default<br />
! Examples<br />
|- valign="top"<br />
| {{Code|[input]}}<br />
|Evaluates the specified input:<br />
* The input string may point to an existing file. If the file suffix is {{Code|.bxs}}, the file contents will be executed as [[Commands#Basics|Command Script]]; any other file content will be evaluated as XQuery expression.<br />
* Otherwise, the input string itself is evaluated as XQuery expression.<br />
|<br />
|<br />
|• {{Code|"doc('X')//head"}}<br/>• {{Code|query.xq}}<br/>• {{Code|commands.bxs}}<br/><br />
|- valign="top"<br />
| {{Code|-b&lt;args&gt;}}<br />
| Binds external variables to XQuery expressions. This flag may be specified multiple times. Variables names and their values are delimited by equality signs (<code>=</code>). The names may be optionally prefixed with dollar signs. If a variable uses a namespace different from the default namespace, it can be specified with the [[XQuery 3.0#Expanded QNames|Expanded QNames]] notation.<br />
| {{Option|BINDINGS}}<br />
|<br />
|• <code>-bv=example "declare variable $v external; $v"</code><br/>• <code>-bQ{URL}ln=value<br/>"declare namespace ns='URL'; declare variable $ns:ln external; $ns:ln"</code><br />
|- valign="top"<br />
| {{Code|-c&lt;input&gt;}}<br />
| Executes [[commands]]. If the specified input is a valid URI or file reference, this file is evaluated as [[Commands#Command_Scripts|Command Script]].<br />
|<br />
|<br />
|• {{Code|-c list}}<br/>• {{Code|-ccommands.txt}}<br/>• {{Code|-c"<info/>"}}<br />
|- valign="top"<br />
| {{Code|-C&lt;file&gt;}}<br />
| Evaluates the contents of the specified file as [[Commands#Command_Scripts|Command Script]].<br />
|<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-d}}<br />
| Toggles the debugging mode. Debugging information is output to ''standard error''.<br />
| {{Option|DEBUG}}<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-i&lt;input&gt;}}<br />
| Opens the specified XML file, directory with XML files, or database. The opened input can then be processed by a command or XQuery expression.<br />
|<br />
|<br />
| {{Code|-iitems.xml "//item"}}<br />
|- valign="top"<br />
| {{Code|-I&lt;input&gt;}}<br />
| Assigns an input string as item of type {{Code|xs:untypedAtomic}} to the query context.<br />
|<br />
|<br />
| {{Code|-I "Hello Universe" -q "."}}<br />
|- valign="top"<br />
| {{Code|-o&lt;path&gt;}}<br />
| All command and query output is written to the specified file.<br />
|<br />
|<br />
| {{Code|-o output.txt}}<br />
|- valign="top"<br />
| {{Code|-q&lt;expr&gt;}}<br />
| Evaluates the specified string as XQuery expression.<br />
|<br />
|<br />
| {{Code|-q"doc('input')//head"}}<br />
|- valign="top"<br />
| {{Code|-Q&lt;file&gt;}}<br />
| Evaluates the contents of the specified file as XQuery expression.<br />
|<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-r&lt;num&gt;}}<br />
| Specifies how often a specified query will be evaluated.<br />
| {{Option|RUNS}}<br />
| <code>1</code><br />
| {{Code|-V -r10 "1"}}<br />
|- valign="top"<br />
| {{Code|-R}}<br />
| Specifies if a query will be evaluated or parsed and compiled only.<br />
| {{Option|RUNQUERY}}<br />
| <code>true</code><br />
| {{Code|-V -R "1"}}<br />
|- valign="top"<br />
| {{Code|-s&lt;args&gt;}}<br />
| Specifies parameters for serializing XQuery results; see [[Serialization]] for more details. This flag may be specified multiple times. Key and values are separated by the equality sign (<code>=</code>).<br />
| {{Option|SERIALIZER}}<br />
|<br />
| <code>-smethod=text</code><br />
|- valign="top"<br />
| {{Code|-t[path]}}<br />
| Runs all [[Unit Module|Unit tests]] in the specified file or directory.<br />
|<br />
|<br />
| -t project/tests<br />
|- valign="top"<br />
| {{Code|-u}}<br />
| Propagates updates on input files back to disk.<br />
| {{Option|WRITEBACK}}<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-v}}<br />
| Toggles the output of process and timing information.<br />
|<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-V}}<br />
| Prints detailed query information to the ''standard output'', including details on the compilation and profiling steps.<br />
| {{Option|QUERYINFO}}<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-w}}<br />
| Toggles whitespace stripping of XML text nodes. By default, whitespaces will be preserved.<br />
| {{Option|STRIPWS}}<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-W}}<br />
| Enables indentation with whitespace. By default, query results will not be indented.<br />
| {{Option|SERIALIZER}}<br />
| <code>indent=no</code><br />
|<br />
|- valign="top"<br />
| {{Code|-x}}<br />
| Toggles the output of the query execution plan, formatted as XML.<br />
| {{Option|XMLPLAN}}<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-z}}<br />
| Turns the serialization of XQuery results on/off. This flag is useful if the query is profiled or analyzed.<br />
| {{Option|SERIALIZE}}<br />
| <code>true</code><br />
|<br />
|}<br />
<br />
=GUI=<br />
<br />
The following options are available for the standalone [[GUI|Graphical User Interface]]:<br />
<br />
<pre><br />
$ basexgui -h<br />
BaseX [GUI]<br />
Usage: basexgui [-d] [files]<br />
[files] Open specified files<br />
-d Enable debugging<br />
</pre><br />
<br />
You can pass one or more files as parameters. If an XML document is specified, a database instance can be created from this file. Other files are opened in the editor.<br />
<br />
=Server=<br />
<br />
{{Announce|Added with Version 11:}} {{Code|-C}}<br />
<br />
The following options are available for the [[Database Server]]:<br />
<br />
<pre><br />
$ basexserver -h<br />
BaseX [Server]<br />
Usage: basexserver [-cdnpSz] [stop]<br />
stop Stop running server<br />
-c<input> Execute commands from file or string<br />
-C<file> Execute command script file<br />
-d Enable debugging output<br />
-n<name> Set host the server is bound to<br />
-p<port> Set server port<br />
-S Start as service<br />
-z Suppress logging<br />
</pre><br />
<br />
Details on all options are listed in the following table (equivalent database options are shown in the table as well).<br />
For the examples to work, it might be necessary to escape some characters depending on your operating system.<br />
<br />
{| class="wikitable"<br />
|- valign="top"<br />
! width='120' | Flag<br />
! width="40%" | Description<br />
! Option<br />
! Default<br />
! Examples<br />
|- valign="top"<br />
| {{Code|stop}}<br />
| Stops a local database server instance and quits.<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-c&lt;input&gt;}}<br />
| Executes [[commands]]. If the specified input is a valid URI or file reference, this file is evaluated as [[Commands#Command_Scripts|Command Script]].<br />
|<br />
|<br />
| {{Code|-c"open database;info"}}<br />
|- valign="top"<br />
| {{Code|-C&lt;file&gt;}}<br />
| Evaluates the contents of the specified file as [[Commands#Command_Scripts|Command Script]].<br />
|<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-d}}<br />
| Enables debugging output. Debugging information is output to ''standard error''.<br />
| {{Option|DEBUG}}<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-n&lt;name&gt;}}<br />
| Specifies the host the server will be bound to.<br />
| {{Option|SERVERHOST}}<br />
|<br />
| {{Code|-p127.0.0.1}}<br />
|- valign="top"<br />
| {{Code|-p&lt;port&gt;}}<br />
| Specifies the port on which the server will be addressable.<br />
| {{Option|SERVERPORT}}<br />
| {{Code|1984}}<br />
| {{Code|-p9999}}<br />
|- valign="top"<br />
| {{Code|-S}}<br />
| Starts the server as service (i.e., in the background). Use [[YAJSW]], or start BaseX as an ordinary background process to get more options.<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-z}}<br />
| Prevents the generation of [[Logging|log files]].<br />
| {{Option|LOG}}<br />
| <code>true</code><br />
|<br />
|}<br />
<br />
Multiple {{Code|-c}} and {{Code|-i}} flags can be specified. All other options will be set before any other operation takes place. The specified inputs, query files, queries and commands will be subsequently evaluated after that in the given order. The standard input can be parsed by specifying a single dash ({{Code|-}}) as argument.<br />
<br />
=Client=<br />
<br />
{{Announce|Added with Version 11:}} {{Code|-C}}, {{Code|-Q}}, {{Code|-W}}<br />
<br />
If the [[Database Server|Database Client]] is launched, you will be requested for a username and password.<br />
<br />
<pre><br />
$ basexclient -h<br />
BaseX [Client]<br />
Usage: basexclient [-bcdiInopPqrRsUvVwxz] [input]<br />
[input] XQuery or command file, or query string<br />
-b<args> Bind external query variables<br />
-c<input> Execute commands from file or string<br />
-C<file> Execute command script file<br />
-d Toggle debugging output<br />
-i<input> Bind file or database to context<br />
-I<input> Bind input string to context<br />
-n<name> Set server (host) name<br />
-o<path> Write output to local file<br />
-p<port> Set server port<br />
-P<pass> Specify user password<br />
-q<expr> Execute XQuery expression<br />
-Q<file> Execute XQuery file<br />
-r<num> Run query multiple times<br />
-R Toggle query execution<br />
-s<args> Set serialization parameters<br />
-U<name> Specify username<br />
-v Toggle output of progress info<br />
-V Toggle detailed query output<br />
-w Toggle whitespace stripping<br />
-W Enable indentation with whitespaces<br />
-x Toggle output of query plan<br />
-z Toggle output of query result<br />
</pre><br />
<br />
See the following table for details (equivalent database options are shown in the table as well).<br />
For the examples to work, it might be necessary to escape some characters, depending on your operating system.<br />
<br />
{| class="wikitable"<br />
|- valign="top"<br />
! width='120' | Flag<br />
! width="40%" | Description<br />
! Option<br />
! Default<br />
! Examples<br />
|- valign="top"<br />
| {{Code|[input]}}<br />
|Evaluates the specified input:<br />
* The input string may point to an existing file. If the file suffix is {{Code|.bxs}}, the file contents will be evaluated as [[Commands#Basics|Command Script]]; any other file content will be evaluated as XQuery expression.<br />
* Otherwise, the input string itself is evaluated as XQuery expression.<br />
|<br />
|<br />
|• {{Code|"doc('X')//head"}}<br/>• {{Code|query.xq}}<br/>• {{Code|commands.bxs}}<br/><br />
|- valign="top"<br />
| {{Code|-b&lt;args&gt;}}<br />
| Binds external variables to XQuery expressions. This flag may be specified multiple times. Variables names and their values are delimited by equality signs (<code>=</code>). The names may be optionally prefixed with dollar signs. If a variable uses a namespace different from the default namespace, it can be specified with the [[XQuery 3.0#Expanded QNames|Expanded QNames]] notation.<br />
| {{Option|BINDINGS}}<br />
|<br />
|• <code>-b$v=example "declare variable $v external; $v"</code><br/>• <code>-b{URL}ln=value<br/>"declare namespace ns='URL'; declare variable $ns:ln external; $ns:ln"</code><br />
|- valign="top"<br />
| {{Code|-c&lt;input&gt;}}<br />
| Executes [[commands]]. If the specified input is a valid URI or file reference, its content will be executed instead. Empty lines and lines starting with the number sign {{Code|#}} will be ignored.<br />
|<br />
|<br />
|• {{Code|-c list}}<br/>• {{Code|-ccommands.txt}}<br/>• {{Code|-c"<info/>"}}<br />
|- valign="top"<br />
| {{Code|-C&lt;file&gt;}}<br />
| Evaluates the contents of the specified file as [[Commands#Command_Scripts|Command Script]].<br />
|<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-d}}<br />
| Toggles the debugging mode. Debugging information is output to ''standard error''.<br />
| {{Option|DEBUG}}<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-i&lt;input&gt;}}<br />
| Opens the specified XML file, directory with XML files, or database. The opened input can then be processed by a command or XQuery expression.<br />
|<br />
|<br />
| {{Code|-iitems.xml "//item"}}<br />
|- valign="top"<br />
| {{Code|-I&lt;input&gt;}}<br />
| Assigns an input string as item of type {{Code|xs:untypedAtomic}} to the query context.<br />
|<br />
|<br />
| {{Code|-I "Hello Universe" -q "."}}<br />
|- valign="top"<br />
| {{Code|-n&lt;name&gt;}}<br />
| Specifies the host name on which the server is running.<br />
| {{Option|HOST}}<br />
| {{Code|localhost}}<br />
| {{Code|-nserver.basex.org}}<br />
|- valign="top"<br />
| {{Code|-o&lt;path&gt;}}<br />
| All command and query output is written to the specified file.<br />
|<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-p&lt;port&gt;}}<br />
| Specifies the port on which the server is running.<br />
| {{Option|PORT}}<br />
| {{Code|1984}}<br />
| {{Code|-p9999}}<br />
|- valign="top"<br />
| {{Code|-P&lt;pass&gt;}}<br />
| Specifies the user password. If this flag is omitted, the password will be requested on command line. ''Warning'': When the password is supplied with this flag, it may end up in logs or the bash history.<br />
| {{Option|PASSWORD}}<br />
|<br />
| {{Code|-Uadmin -P...}}<br />
|- valign="top"<br />
| {{Code|-q&lt;expr&gt;}}<br />
| Executes the specified string as XQuery expression.<br />
|<br />
| {{Code|-q"1+2"}}<br />
|- valign="top"<br />
| {{Code|-Q&lt;file&gt;}}<br />
| Evaluates the contents of the specified file as XQuery expression.<br />
|<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-r&lt;num&gt;}}<br />
| Specifies how often a specified query will be evaluated.<br />
| {{Option|RUNS}}<br />
| <code>1</code><br />
| {{Code|-V -r10 "1"}}<br />
|- valign="top"<br />
| {{Code|-R}}<br />
| Specifies if a query will be executed or parsed only.<br />
| {{Option|RUNQUERY}}<br />
| <code>true</code><br />
| {{Code|-V -R "1"}}<br />
|- valign="top"<br />
| {{Code|-s&lt;args&gt;}}<br />
| Specifies parameters for serializing XQuery results; see [[Serialization]] for more details. This flag may be specified multiple times. Key and values are separated by the equality sign (<code>=</code>).<br />
| {{Option|SERIALIZER}}<br />
|<br />
| <code>-smethod=text</code><br />
|- valign="top"<br />
| {{Code|-U&lt;name&gt;}}<br />
| Specifies the username. If this flag is omitted, the username will be requested on command line.<br />
| {{Option|USER}}<br />
|<br />
| {{Code|-Uadmin}}<br />
|- valign="top"<br />
| {{Code|-v}}<br />
| Prints process and timing information to the ''standard output''.<br />
|<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-V}}<br />
| Prints detailed query information to the ''standard output'', including details on the compilation and profiling steps.<br />
| {{Option|QUERYINFO}}<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-w}}<br />
| Toggles whitespace stripping of XML text nodes. By default, whitespaces will be preserved.<br />
| {{Option|STRIPWS}}<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-W}}<br />
| Enables indentation with whitespace. By default, query results will not be indented.<br />
| {{Option|SERIALIZER}}<br />
| <code>indent=no</code><br />
|<br />
|- valign="top"<br />
| {{Code|-x}}<br />
| Toggles the output of the query execution plan, formatted as XML.<br />
| {{Option|XMLPLAN}}<br />
| <code>false</code><br />
|<br />
|- valign="top"<br />
| {{Code|-z}}<br />
| Turns the serialization of XQuery results on/off. This flag is useful if the query is profiled or analyzed.<br />
| {{Option|SERIALIZE}}<br />
| <code>true</code><br />
|<br />
|}<br />
<br />
=HTTP Server=<br />
<br />
{{Announce|Added with Version 11:}} {{Code|-C}}<br />
<br />
The following options are available for the [[Web Application|HTTP Server]]:<br />
<br />
<pre><br />
$ basexhttp -h<br />
BaseX [HTTP]<br />
Usage: basexhttp [-cdhlnpsSUz] [stop]<br />
stop Stop running server<br />
-c<input> Execute commands from file or string<br />
-C<file> Execute command script file<br />
-d Enable debugging output<br />
-g Enable GZIP support<br />
-h<port> Set port of HTTP server<br />
-l Start in local mode<br />
-n<name> Set host name of database server<br />
-p<port> Set port of database server<br />
-s<port> Specify port to stop HTTP server<br />
-S Start as service<br />
-U<name> Specify username<br />
-z Suppress logging<br />
</pre><br />
<br />
The meaning of all options is listed in the following table (equivalent database options are shown in the table as well).<br />
For the examples to work, it might be necessary to escape some characters depending on your Operating System.<br />
<br />
{| class="wikitable"<br />
|- valign="top"<br />
! width='120' | Flag<br />
! width="40%" | Description<br />
! Option<br />
! Default<br />
! Examples<br />
|- valign="top"<br />
| {{Code|stop}}<br />
| Stops a local HTTP server and quits. The database server will be stopped as well, unless {{Code|-l}} is specified.<br />
| <code>pom.xml</code><br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-c&lt;input&gt;}}<br />
| Executes [[commands]]. If the specified input is a valid URI or file reference, this file is evaluated as [[Commands#Command_Scripts|Command Script]].<br />
|<br />
|<br />
| {{Code|-c"open database"}}<br />
|- valign="top"<br />
| {{Code|-C&lt;file&gt;}}<br />
| Evaluates the contents of the specified file as [[Commands#Command_Scripts|Command Script]].<br />
|<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-e}}<br />
| Enables debugging output. Debugging information is output to ''standard error''.<br />
| {{Option|DEBUG}}<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-g}}<br />
| Enables GZIP support in Jetty.<br />
| {{Option|GZIP}}<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-h&lt;port&gt;}}<br />
| Specifies the port on which the HTTP server will be addressable.<br />
| <code>jetty.xml</code><br />
| {{Code|8080}}<br />
| {{Code|-h9999}}<br />
|- valign="top"<br />
| {{Code|-l}}<br />
| Starts the server in ''local mode'', and executes all commands in the embedded database context.<br />
| {{Option|HTTPLOCAL}}<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-n&lt;name&gt;}}<br />
| Specifies the host name on which the server is running.<br />
| {{Option|HOST}}<br />
| {{Code|localhost}}<br />
| {{Code|-nserver.basex.org}}<br />
|- valign="top"<br />
| {{Code|-p&lt;port&gt;}}<br />
| Specifies the port on which the database server will be addressable.<br />
| {{Option|SERVERPORT}}<br />
| {{Code|1984}}<br />
| {{Code|-p9998}}<br />
|- valign="top"<br />
| {{Code|-s&lt;port&gt;}}<br />
| Specifies the port that will be used to stop the HTTP server.<br />
| {{Option|STOPPORT}} or<br/><code>pom.xml</code><br />
| <code>8081</code><br />
|<br />
|- valign="top"<br />
| {{Code|-S}}<br />
| Starts the server as service (i.e., in the background). Use [[YAJSW]], or start BaseX as an ordinary background process to get more options.<br />
|<br />
|<br />
|- valign="top"<br />
| {{Code|-U&lt;name&gt;}}<br />
| Specifies a username, which will be used by the HTTP services for opening a new session.<br />
| {{Option|USER}}<br />
|<br />
| {{Code|-Uadmin}}<br />
|- valign="top"<br />
| {{Code|-z}}<br />
| Prevents the generation of [[Logging|log files]].<br />
| {{Option|LOG}}<br />
|<br />
|}<br />
<br />
=Changelog=<br />
<br />
;Version 11.0<br />
* Added: {{Code|-C}} (standalone, server, client, HTTP server).<br />
* Added: {{Code|-Q}}, {{Code|-W}} (standalone, client).<br />
* Updated: The Clark notation was replaced with the [[XQuery 3.0#Expanded QNames|Expanded QNames]] notation.<br />
<br />
;Version 10.0<br />
* Updated: Whitespaces are now preserved by default (see {{Option|STRIPWS}} for more details).<br />
<br />
;Version 9.0<br />
* Added: BaseXHTTP, command-line option {{Code|-c}}.<br />
* Updated: BaseXHTTP, command-line option {{Code|-c}}, additionally accepts valid URLs and file references.<br />
<br />
;Version 8.2<br />
* Removed: Event ports, {{Code|-e}}.<br />
<br />
;Version 8.1<br />
* Added: Bind input strings to the query context with {{Code|-I}}.<br />
<br />
;Version 8.0<br />
* Removed: Command-line option <code>-L</code> (results will now be automatically separated by newlines).<br />
<br />
;Version 7.9<br />
* Added: Runs tests in file or directory with {{Code|-t}}.<br />
* Removed: interactive server mode.<br />
<br />
;Version 7.8<br />
* Added: Specify if a query will be executed or parsed only with {{Code|-R}}.<br />
<br />
;Version 7.7<br />
* Added: Bind host to the [[#BaseX Server|BaseX Server]] with {{Code|-n}}.<br />
<br />
;Version 7.5<br />
* Added: detection of [[Commands#Basics|Command Scripts]].<br />
* Removed: HTTP server flags {{Code|-R}}, {{Code|-W}}, and {{Code|-X}}.<br />
<br />
; Version 7.3:<br />
* Updated: all options are now evaluated in the given order.<br />
* Updated: Create main-memory representations for specified sources with {{Code|-i}}.<br />
* Updated: Options {{Code|-C}}/{{Code|-c}} and {{Code|-q}}/{{Code|[input]}} merged.<br />
* Updated: Option {{Code|-L}} also separates serialized items with newlines (instead of spaces).<br />
<br />
; Version 7.2:<br />
* Added: RESTXQ Service<br />
<br />
; Version 7.1.1:<br />
* Added: Options {{Code|-C}} and {{Code|-L}} in standalone and client mode.<br />
<br />
; Version 7.1:<br />
* Updated: Multiple query files and {{Code|-c}}/{{Code|-i}}/{{Code|-q}} flags can be specified.</div>Andy Buncehttps://docs.basex.org/index.php?title=Binary_Module&diff=16628Binary Module2023-09-11T13:01:23Z<p>Andy Bunce: move comma</p>
<hr />
<div>This [[Module Library|XQuery Module]] contains functions to process binary data, including extracting subparts, searching, basic binary operations and conversion between binary and structured forms.<br />
<br />
This module is based on the [http://expath.org/spec/binary EXPath Binary Module].<br />
<br />
=Conventions=<br />
<br />
All functions and errors in this module are assigned to the <code><nowiki>http://expath.org/ns/binary</nowiki></code> namespace, which is statically bound to the {{Code|bin}} prefix.<br/><br />
<br />
=Constants and Conversions=<br />
<br />
==bin:hex==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:hex(<br />
$in as xs:string?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the binary form of the set of octets written as a sequence of (ASCII) hex digits ([0-9A-Fa-f]).<br/>{{Code|$in}} will be effectively zero-padded from the left to generate an integral number of octets, i.e. an even number of hexadecimal digits. If {{Code|$in}} is an empty string, then the result will be an {{Code|xs:base64Binary}} with no embedded data. Byte order in the result follows (per-octet) character order in the string. If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|non-numeric-character|#Errors}} the input cannot be parsed as a hexadecimal number.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<code>string(bin:hex('11223F4E'))</code> yields <code>ESI/Tg==</code>.<br/><code>string(xs:hexBinary(bin:hex('FF')))</code> yields <code>FF</code>.<br />
|}<br />
<br />
==bin:bin==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:bin(<br />
$in as xs:string?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the binary form of the set of octets written as a sequence of (8-wise) (ASCII) binary digits ([01]).<br/><code>$in</code> will be effectively zero-padded from the left to generate an integral number of octets. If <code>$in</code> is an empty string, then the result will be an <code>xs:base64Binary</code> with no embedded data. Byte order in the result follows (per-octet) character order in the string. If the value of <code>$in</code> is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|non-numeric-character|#Errors}} the input cannot be parsed as a binary number.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<code>string(bin:bin('1101000111010101'))</code> yields <code>0dU=</code>.<br/><code>string(xs:hexBinary(bin:bin('1000111010101')))</code> yields <code>11D5</code>.<br />
|}<br />
<br />
==bin:octal==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:octal(<br />
$in as xs:string?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the binary form of the set of octets written as a sequence of (ASCII) octal digits ([0-7]).<br/><code>$in</code> will be effectively zero-padded from the left to generate an integral number of octets. If <code>$in</code> is an empty string, then the result will be an <code>xs:base64Binary</code> with no embedded data. Byte order in the result follows (per-octet) character order in the string. If the value of <code>$in</code> is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|non-numeric-character|#Errors}} the input cannot be parsed as an octal number.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<code>string(xs:hexBinary(bin:octal('11223047')))</code> yields <code>252627</code>.<br />
|}<br />
<br />
==bin:to-octets==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:to-octets(<br />
$in as xs:base64Binary<br />
) as xs:integer*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns binary data as a sequence of octets.<br/>If <code>$in</code> is a zero length binary data then the empty sequence is returned. Octets are returned as integers from 0 to 255.<br />
|}<br />
<br />
==bin:from-octets==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:from-octets(<br />
$in as xs:integer*<br />
) as xs:base64Binary</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Converts a sequence of octets into binary data.<br/>Octets are integers from 0 to 255. If the value of <code>$in</code> is the empty sequence, the function returns zero-sized binary data.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|octet-out-of-range|#Errors}} one of the octets lies outside the range 0 - 255.<br />
|}<br />
<br />
=Basic Operations=<br />
<br />
==bin:length==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:length(<br />
$in as xs:base64Binary<br />
) as xs:integer</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the size of binary data in octets.<br />
|}<br />
<br />
==bin:part==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:part(<br />
$in as xs:base64Binary?,<br />
$offset as xs:integer,<br />
$size as xs:integer := ()<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns a section of binary data starting at the {{Code|$offset}} octet.<br/>If {{Code|$size}} is specified, the size of the returned binary data is {{Code|$size}} octets. If {{Code|$size}} is absent, all remaining data from {{Code|$offset}} is returned. The {{Code|$offset}} is zero based. If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|negative-size|#Errors}} the specified size is negative.<br/>{{Error|index-out-of-range|#Errors}} the specified offset + size is out of range.<br />
|- valign="top"<br />
| '''Examples'''<br />
|Test whether binary data starts with binary content consistent with a PDF file:<br/><code>bin:part($data, 0, 4) eq bin:hex("25504446")</code>.<br />
|}<br />
<br />
==bin:join==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:join(<br />
$in as xs:base64Binary*<br />
) as xs:base64Binary</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns an {{Code|xs:base64Binary}} created by concatenating the items in the sequence {{Code|$in}}, in order. If the value of {{Code|$in}} is the empty sequence, the function returns a binary item containing no data bytes.<br />
|}<br />
<br />
==bin:insert-before==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:insert-before(<br />
$in as xs:base64Binary?,<br />
$offset as xs:integer,<br />
$extra as xs:base64Binary?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns binary data consisting sequentially of the data from {{Code|$in}} up to and including the {{Code|$offset - 1}} octet, followed by all the data from {{Code|$extra}}, and then the remaining data from {{Code|$in}}.<br/>The {{Code|$offset}} is zero based. If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|index-out-of-range|#Errors}} the specified offset is out of range.<br />
|}<br />
<br />
==bin:pad-left==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:pad-left(<br />
$in as xs:base64Binary?,<br />
$size as xs:integer,<br />
$octet as xs:integer := ()<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns an {{Code|xs:base64Binary}} created by padding the input with {{Code|$size}} octets in front of the input. If {{Code|$octet}} is specified, the padding octets each have that value, otherwise they are zero.<br/>If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|negative-size|#Errors}} the specified size is negative.<br/>{{Error|octet-out-of-range|#Errors}} the specified octet lies outside the range 0-255.<br />
|}<br />
<br />
==bin:pad-right==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:pad-right(<br />
$in as xs:base64Binary?,<br />
$size as xs:integer,<br />
$octet as xs:integer := ()<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns an {{Code|xs:base64Binary}} created by padding the input with {{Code|$size}} octets after the input. If {{Code|$octet}} is specified, the padding octets each have that value, otherwise they are zero.<br/>If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|negative-size|#Errors}} the specified size is negative.<br/>{{Error|octet-out-of-range|#Errors}} the specified octet lies outside the range 0-255.<br />
|}<br />
<br />
==bin:find==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:find(<br />
$in as xs:base64Binary?,<br />
$offset as xs:integer,<br />
$search as xs:base64Binary<br />
) as xs:integer?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the first location of the binary search sequence in the input, or if not found, the empty sequence.<br/>The {{Code|$offset}} and the returned location are zero based. If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|index-out-of-range|#Errors}} the specified offset + size is out of range.<br />
|}<br />
<br />
=Text Decoding and Encoding=<br />
<br />
==bin:decode-string==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:decode-string(<br />
$in as xs:base64Binary?,<br />
$encoding as xs:string := 'utf-8',<br />
$offset as xs:integer := (),<br />
$size as xs:integer := ()<br />
) as xs:string?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Decodes binary data as a string in a given {{Code|$encoding}}.<br/>If {{Code|$offset}} and {{Code|$size}} are provided, the {{Code|$size}} octets from {{Code|$offset}} are decoded. If {{Code|$offset}} alone is provided, octets from {{Code|$offset}} to the end are decoded.If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|negative-size|#Errors}} the specified size is negative.<br/>{{Error|index-out-of-range|#Errors}} the specified offset + size is out of range.<br/>{{Error|unknown-encoding|#Errors}} the specified encoding is unknown.<br/>{{Error|conversion-error|#Errors}} an error or malformed input occurred during decoding the string.<br />
|- valign="top"<br />
| '''Examples'''<br />
|Tests whether the binary data starts with binary content consistent with a PDF file:<br/><code>bin:decode-string($data, 'UTF-8', 0, 4) eq '%PDF'</code>.<br />
|}<br />
<br />
==bin:encode-string==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:encode-string(<br />
$in as xs:string?,<br />
$encoding as xs:string := 'utf-8'<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Encodes a string into binary data using a given {{Code|$encoding}}.<br/>If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|unknown-encoding|#Errors}} the specified encoding is unknown.<br/>{{Error|conversion-error|#Errors}} an error or malformed input occurred during encoding the string.<br />
|}<br />
<br />
=Packing and Unpacking of Numeric Values=<br />
<br />
The functions have an optional parameter $octet-order whose string value controls the order: Least-significant-first order is indicated by any of the values {{Code|least-significant-first}}, {{Code|little-endian}}, or {{Code|LE}}. Most-significant-first order is indicated by any of the values {{Code|most-significant-first}}, {{Code|big-endian}}, or {{Code|BE}}.<br />
<br />
==bin:pack-double==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:pack-double(<br />
$in as xs:double,<br />
$octet-order as xs:string := ()<br />
) as xs:base64Binary</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the 8-octet binary representation of a double value.<br/>Most-significant-octet-first number representation is assumed unless the {{Code|$octet-order}} parameter is specified.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|unknown-significance-order|#Errors}} the specified octet order is unknown.<br />
|}<br />
<br />
==bin:pack-float==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:pack-float(<br />
$in as xs:float,<br />
$octet-order as xs:string := ()<br />
) as xs:base64Binary</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the 4-octet binary representation of a float value.<br/>Most-significant-octet-first number representation is assumed unless the {{Code|$octet-order}} parameter is specified.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|unknown-significance-order|#Errors}} the specified octet order is unknown.<br />
|}<br />
<br />
==bin:pack-integer==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:pack-integer(<br />
$in as xs:integer,<br />
$size as xs:integer,<br />
$octet-order as xs:string := ()<br />
) as xs:base64Binary</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the twos-complement binary representation of an integer value treated as {{Code|$size}} octets long. Any 'excess' high-order bits are discarded.<br/>Most-significant-octet-first number representation is assumed unless the {{Code|$octet-order}} parameter is specified. Specifying a {{Code|$size}} of zero yields an empty binary data.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|unknown-significance-order|#Errors}} the specified octet order is unknown.<br/>{{Error|negative-size|#Errors}} the specified size is negative.<br/><br />
|}<br />
<br />
==bin:unpack-double==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:unpack-double(<br />
$in as xs:base64Binary,<br />
$offset as xs:integer,<br />
$octet-order as xs:string := ()<br />
) as xs:double</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Extracts the double value stored at the particular offset in binary data.<br/>Most-significant-octet-first number representation is assumed unless the {{Code|$octet-order}} parameter is specified. The {{Code|$offset}} is zero based.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|index-out-of-range|#Errors}} the specified offset is out of range.<br/>{{Error|unknown-significance-order|#Errors}} the specified octet order is unknown.<br />
|}<br />
<br />
==bin:unpack-float==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:unpack-float(<br />
$in as xs:base64Binary,<br />
$offset as xs:integer,<br />
$octet-order as xs:string := ()<br />
) as xs:float</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Extracts the float value stored at the particular offset in binary data.<br/>Most-significant-octet-first number representation is assumed unless the {{Code|$octet-order}} parameter is specified. The {{Code|$offset}} is zero based.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|index-out-of-range|#Errors}} the specified offset + size is out of range.<br/>{{Error|unknown-significance-order|#Errors}} the specified octet order is unknown.<br />
|}<br />
<br />
==bin:unpack-integer==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:unpack-integer(<br />
$in as xs:base64Binary,<br />
$offset as xs:integer,<br />
$size as xs:integer,<br />
$octet-order as xs:string := ()<br />
) as xs:integer</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns a signed integer value represented by the {{Code|$size}} octets starting from {{Code|$offset}} in the input binary representation. Necessary sign extension is performed (i.e. the result is negative if the high order bit is '1').<br/>Most-significant-octet-first number representation is assumed unless the {{Code|$octet-order}} parameter is specified. The {{Code|$offset}} is zero based. Specifying a {{Code|$size}} of zero yields the integer {{Code|0}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|negative-size|#Errors}} the specified size is negative.<br/>{{Error|index-out-of-range|#Errors}} the specified offset + size is out of range.<br/>{{Error|unknown-significance-order|#Errors}} the specified octet order is unknown.<br />
|}<br />
<br />
==bin:unpack-unsigned-integer==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:unpack-unsigned-integer(<br />
$in as xs:base64Binary,<br />
$offset as xs:integer,<br />
$size as xs:integer,<br />
$octet-order as xs:string := ()<br />
) as xs:integer</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns an unsigned integer value represented by the {{Code|$size}} octets starting from {{Code|$offset}} in the input binary representation.<br/>Most-significant-octet-first number representation is assumed unless the {{Code|$octet-order}} parameter is specified. The {{Code|$offset}} is zero based. Specifying a {{Code|$size}} of zero yields the integer {{Code|0}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|negative-size|#Errors}} the specified size is negative.<br/>{{Error|index-out-of-range|#Errors}} the specified offset + size is out of range.<br/>{{Error|unknown-significance-order|#Errors}} the specified octet order is unknown.<br />
|}<br />
<br />
=Bitwise Operations=<br />
<br />
==bin:or==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:or(<br />
$a as xs:base64Binary?,<br />
$b as xs:base64Binary?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the "bitwise or" of two binary arguments.<br/>If either argument is the empty sequence, an empty sequence is returned.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|differing-length-arguments|#Errors}} the input arguments are of differing length.<br />
|}<br />
<br />
==bin:xor==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:xor(<br />
$a as xs:base64Binary?,<br />
$b as xs:base64Binary?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the "bitwise xor" of two binary arguments.<br/>If either argument is the empty sequence, an empty sequence is returned.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|differing-length-arguments|#Errors}} the input arguments are of differing length.<br />
|}<br />
<br />
==bin:and==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:and(<br />
$a as xs:base64Binary?,<br />
$b as xs:base64Binary?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the "bitwise and" of two binary arguments.<br/>If either argument is the empty sequence, an empty sequence is returned.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|differing-length-arguments|#Errors}} the input arguments are of differing length.<br />
|}<br />
<br />
==bin:not==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:not(<br />
$in as xs:base64Binary?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the "bitwise not" of a binary argument.<br/>If the argument is the empty sequence, an empty sequence is returned.<br />
|}<br />
<br />
==bin:shift==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:shift(<br />
$in as xs:base64Binary?,<br />
$by as xs:integer<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Shifts bits in binary data.<br/>If {{Code|$by}} is zero, the result is identical to {{Code|$in}}. If {{Code|$by}} is positive then bits are shifted to the left. Otherwise, bits are shifted to the right. If the absolute value of <code>$by</code> is greater than the bit-length of {{Code|$in}} then an all-zeros result is returned. The result always has the same size as {{Code|$in}}. The shifting is logical: zeros are placed into discarded bits. If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|}<br />
<br />
=Errors=<br />
<br />
{| class="wikitable" width="100%"<br />
! width="240"|Code<br />
|Description<br />
|- valign="top"<br />
|{{Code|differing-length-arguments}} <br />
|The arguments to a bitwise operation have different lengths.<br />
|- valign="top"<br />
|{{Code|index-out-of-range}}<br />
|An offset value is out of range.<br />
|- valign="top"<br />
|{{Code|negative-size}}<br />
|A size value is negative.<br />
|- valign="top"<br />
|{{Code|octet-out-of-range}}<br />
|An octet value lies outside the range 0-255.<br />
|- valign="top"<br />
|{{Code|non-numeric-character}}<br />
|Binary data cannot be parsed as number.<br />
|- valign="top"<br />
|{{Code|unknown-encoding}}<br />
|An encoding is not supported.<br />
|- valign="top"<br />
|{{Code|conversion-error}}<br />
|An error or malformed input during converting a string.<br />
|- valign="top"<br />
|{{Code|unknown-significance-order}}<br />
|An octet-order value is unknown.<br />
|}<br />
<br />
=Changelog=<br />
<br />
Introduced with Version 7.8.</div>Andy Buncehttps://docs.basex.org/index.php?title=Binary_Module&diff=16627Binary Module2023-09-11T12:59:15Z<p>Andy Bunce: bin:decode-string $encoding optional</p>
<hr />
<div>This [[Module Library|XQuery Module]] contains functions to process binary data, including extracting subparts, searching, basic binary operations and conversion between binary and structured forms.<br />
<br />
This module is based on the [http://expath.org/spec/binary EXPath Binary Module].<br />
<br />
=Conventions=<br />
<br />
All functions and errors in this module are assigned to the <code><nowiki>http://expath.org/ns/binary</nowiki></code> namespace, which is statically bound to the {{Code|bin}} prefix.<br/><br />
<br />
=Constants and Conversions=<br />
<br />
==bin:hex==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:hex(<br />
$in as xs:string?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the binary form of the set of octets written as a sequence of (ASCII) hex digits ([0-9A-Fa-f]).<br/>{{Code|$in}} will be effectively zero-padded from the left to generate an integral number of octets, i.e. an even number of hexadecimal digits. If {{Code|$in}} is an empty string, then the result will be an {{Code|xs:base64Binary}} with no embedded data. Byte order in the result follows (per-octet) character order in the string. If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|non-numeric-character|#Errors}} the input cannot be parsed as a hexadecimal number.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<code>string(bin:hex('11223F4E'))</code> yields <code>ESI/Tg==</code>.<br/><code>string(xs:hexBinary(bin:hex('FF')))</code> yields <code>FF</code>.<br />
|}<br />
<br />
==bin:bin==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:bin(<br />
$in as xs:string?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the binary form of the set of octets written as a sequence of (8-wise) (ASCII) binary digits ([01]).<br/><code>$in</code> will be effectively zero-padded from the left to generate an integral number of octets. If <code>$in</code> is an empty string, then the result will be an <code>xs:base64Binary</code> with no embedded data. Byte order in the result follows (per-octet) character order in the string. If the value of <code>$in</code> is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|non-numeric-character|#Errors}} the input cannot be parsed as a binary number.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<code>string(bin:bin('1101000111010101'))</code> yields <code>0dU=</code>.<br/><code>string(xs:hexBinary(bin:bin('1000111010101')))</code> yields <code>11D5</code>.<br />
|}<br />
<br />
==bin:octal==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:octal(<br />
$in as xs:string?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the binary form of the set of octets written as a sequence of (ASCII) octal digits ([0-7]).<br/><code>$in</code> will be effectively zero-padded from the left to generate an integral number of octets. If <code>$in</code> is an empty string, then the result will be an <code>xs:base64Binary</code> with no embedded data. Byte order in the result follows (per-octet) character order in the string. If the value of <code>$in</code> is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|non-numeric-character|#Errors}} the input cannot be parsed as an octal number.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<code>string(xs:hexBinary(bin:octal('11223047')))</code> yields <code>252627</code>.<br />
|}<br />
<br />
==bin:to-octets==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:to-octets(<br />
$in as xs:base64Binary<br />
) as xs:integer*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns binary data as a sequence of octets.<br/>If <code>$in</code> is a zero length binary data then the empty sequence is returned. Octets are returned as integers from 0 to 255.<br />
|}<br />
<br />
==bin:from-octets==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:from-octets(<br />
$in as xs:integer*<br />
) as xs:base64Binary</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Converts a sequence of octets into binary data.<br/>Octets are integers from 0 to 255. If the value of <code>$in</code> is the empty sequence, the function returns zero-sized binary data.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|octet-out-of-range|#Errors}} one of the octets lies outside the range 0 - 255.<br />
|}<br />
<br />
=Basic Operations=<br />
<br />
==bin:length==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:length(<br />
$in as xs:base64Binary<br />
) as xs:integer</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the size of binary data in octets.<br />
|}<br />
<br />
==bin:part==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:part(<br />
$in as xs:base64Binary?,<br />
$offset as xs:integer,<br />
$size as xs:integer := ()<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns a section of binary data starting at the {{Code|$offset}} octet.<br/>If {{Code|$size}} is specified, the size of the returned binary data is {{Code|$size}} octets. If {{Code|$size}} is absent, all remaining data from {{Code|$offset}} is returned. The {{Code|$offset}} is zero based. If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|negative-size|#Errors}} the specified size is negative.<br/>{{Error|index-out-of-range|#Errors}} the specified offset + size is out of range.<br />
|- valign="top"<br />
| '''Examples'''<br />
|Test whether binary data starts with binary content consistent with a PDF file:<br/><code>bin:part($data, 0, 4) eq bin:hex("25504446")</code>.<br />
|}<br />
<br />
==bin:join==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:join(<br />
$in as xs:base64Binary*<br />
) as xs:base64Binary</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns an {{Code|xs:base64Binary}} created by concatenating the items in the sequence {{Code|$in}}, in order. If the value of {{Code|$in}} is the empty sequence, the function returns a binary item containing no data bytes.<br />
|}<br />
<br />
==bin:insert-before==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:insert-before(<br />
$in as xs:base64Binary?,<br />
$offset as xs:integer,<br />
$extra as xs:base64Binary?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns binary data consisting sequentially of the data from {{Code|$in}} up to and including the {{Code|$offset - 1}} octet, followed by all the data from {{Code|$extra}}, and then the remaining data from {{Code|$in}}.<br/>The {{Code|$offset}} is zero based. If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|index-out-of-range|#Errors}} the specified offset is out of range.<br />
|}<br />
<br />
==bin:pad-left==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:pad-left(<br />
$in as xs:base64Binary?,<br />
$size as xs:integer,<br />
$octet as xs:integer := ()<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns an {{Code|xs:base64Binary}} created by padding the input with {{Code|$size}} octets in front of the input. If {{Code|$octet}} is specified, the padding octets each have that value, otherwise they are zero.<br/>If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|negative-size|#Errors}} the specified size is negative.<br/>{{Error|octet-out-of-range|#Errors}} the specified octet lies outside the range 0-255.<br />
|}<br />
<br />
==bin:pad-right==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:pad-right(<br />
$in as xs:base64Binary?,<br />
$size as xs:integer,<br />
$octet as xs:integer := ()<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns an {{Code|xs:base64Binary}} created by padding the input with {{Code|$size}} octets after the input. If {{Code|$octet}} is specified, the padding octets each have that value, otherwise they are zero.<br/>If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|negative-size|#Errors}} the specified size is negative.<br/>{{Error|octet-out-of-range|#Errors}} the specified octet lies outside the range 0-255.<br />
|}<br />
<br />
==bin:find==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:find(<br />
$in as xs:base64Binary?,<br />
$offset as xs:integer,<br />
$search as xs:base64Binary<br />
) as xs:integer?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the first location of the binary search sequence in the input, or if not found, the empty sequence.<br/>The {{Code|$offset}} and the returned location are zero based. If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|index-out-of-range|#Errors}} the specified offset + size is out of range.<br />
|}<br />
<br />
=Text Decoding and Encoding=<br />
<br />
==bin:decode-string==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:decode-string(<br />
$in as xs:base64Binary?,<br />
$encoding as xs:string, := 'utf-8'<br />
$offset as xs:integer := (),<br />
$size as xs:integer := ()<br />
) as xs:string?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Decodes binary data as a string in a given {{Code|$encoding}}.<br/>If {{Code|$offset}} and {{Code|$size}} are provided, the {{Code|$size}} octets from {{Code|$offset}} are decoded. If {{Code|$offset}} alone is provided, octets from {{Code|$offset}} to the end are decoded.If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|negative-size|#Errors}} the specified size is negative.<br/>{{Error|index-out-of-range|#Errors}} the specified offset + size is out of range.<br/>{{Error|unknown-encoding|#Errors}} the specified encoding is unknown.<br/>{{Error|conversion-error|#Errors}} an error or malformed input occurred during decoding the string.<br />
|- valign="top"<br />
| '''Examples'''<br />
|Tests whether the binary data starts with binary content consistent with a PDF file:<br/><code>bin:decode-string($data, 'UTF-8', 0, 4) eq '%PDF'</code>.<br />
|}<br />
<br />
==bin:encode-string==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:encode-string(<br />
$in as xs:string?,<br />
$encoding as xs:string := 'utf-8'<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Encodes a string into binary data using a given {{Code|$encoding}}.<br/>If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|unknown-encoding|#Errors}} the specified encoding is unknown.<br/>{{Error|conversion-error|#Errors}} an error or malformed input occurred during encoding the string.<br />
|}<br />
<br />
=Packing and Unpacking of Numeric Values=<br />
<br />
The functions have an optional parameter $octet-order whose string value controls the order: Least-significant-first order is indicated by any of the values {{Code|least-significant-first}}, {{Code|little-endian}}, or {{Code|LE}}. Most-significant-first order is indicated by any of the values {{Code|most-significant-first}}, {{Code|big-endian}}, or {{Code|BE}}.<br />
<br />
==bin:pack-double==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:pack-double(<br />
$in as xs:double,<br />
$octet-order as xs:string := ()<br />
) as xs:base64Binary</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the 8-octet binary representation of a double value.<br/>Most-significant-octet-first number representation is assumed unless the {{Code|$octet-order}} parameter is specified.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|unknown-significance-order|#Errors}} the specified octet order is unknown.<br />
|}<br />
<br />
==bin:pack-float==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:pack-float(<br />
$in as xs:float,<br />
$octet-order as xs:string := ()<br />
) as xs:base64Binary</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the 4-octet binary representation of a float value.<br/>Most-significant-octet-first number representation is assumed unless the {{Code|$octet-order}} parameter is specified.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|unknown-significance-order|#Errors}} the specified octet order is unknown.<br />
|}<br />
<br />
==bin:pack-integer==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:pack-integer(<br />
$in as xs:integer,<br />
$size as xs:integer,<br />
$octet-order as xs:string := ()<br />
) as xs:base64Binary</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the twos-complement binary representation of an integer value treated as {{Code|$size}} octets long. Any 'excess' high-order bits are discarded.<br/>Most-significant-octet-first number representation is assumed unless the {{Code|$octet-order}} parameter is specified. Specifying a {{Code|$size}} of zero yields an empty binary data.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|unknown-significance-order|#Errors}} the specified octet order is unknown.<br/>{{Error|negative-size|#Errors}} the specified size is negative.<br/><br />
|}<br />
<br />
==bin:unpack-double==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:unpack-double(<br />
$in as xs:base64Binary,<br />
$offset as xs:integer,<br />
$octet-order as xs:string := ()<br />
) as xs:double</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Extracts the double value stored at the particular offset in binary data.<br/>Most-significant-octet-first number representation is assumed unless the {{Code|$octet-order}} parameter is specified. The {{Code|$offset}} is zero based.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|index-out-of-range|#Errors}} the specified offset is out of range.<br/>{{Error|unknown-significance-order|#Errors}} the specified octet order is unknown.<br />
|}<br />
<br />
==bin:unpack-float==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:unpack-float(<br />
$in as xs:base64Binary,<br />
$offset as xs:integer,<br />
$octet-order as xs:string := ()<br />
) as xs:float</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Extracts the float value stored at the particular offset in binary data.<br/>Most-significant-octet-first number representation is assumed unless the {{Code|$octet-order}} parameter is specified. The {{Code|$offset}} is zero based.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|index-out-of-range|#Errors}} the specified offset + size is out of range.<br/>{{Error|unknown-significance-order|#Errors}} the specified octet order is unknown.<br />
|}<br />
<br />
==bin:unpack-integer==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:unpack-integer(<br />
$in as xs:base64Binary,<br />
$offset as xs:integer,<br />
$size as xs:integer,<br />
$octet-order as xs:string := ()<br />
) as xs:integer</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns a signed integer value represented by the {{Code|$size}} octets starting from {{Code|$offset}} in the input binary representation. Necessary sign extension is performed (i.e. the result is negative if the high order bit is '1').<br/>Most-significant-octet-first number representation is assumed unless the {{Code|$octet-order}} parameter is specified. The {{Code|$offset}} is zero based. Specifying a {{Code|$size}} of zero yields the integer {{Code|0}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|negative-size|#Errors}} the specified size is negative.<br/>{{Error|index-out-of-range|#Errors}} the specified offset + size is out of range.<br/>{{Error|unknown-significance-order|#Errors}} the specified octet order is unknown.<br />
|}<br />
<br />
==bin:unpack-unsigned-integer==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:unpack-unsigned-integer(<br />
$in as xs:base64Binary,<br />
$offset as xs:integer,<br />
$size as xs:integer,<br />
$octet-order as xs:string := ()<br />
) as xs:integer</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns an unsigned integer value represented by the {{Code|$size}} octets starting from {{Code|$offset}} in the input binary representation.<br/>Most-significant-octet-first number representation is assumed unless the {{Code|$octet-order}} parameter is specified. The {{Code|$offset}} is zero based. Specifying a {{Code|$size}} of zero yields the integer {{Code|0}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|negative-size|#Errors}} the specified size is negative.<br/>{{Error|index-out-of-range|#Errors}} the specified offset + size is out of range.<br/>{{Error|unknown-significance-order|#Errors}} the specified octet order is unknown.<br />
|}<br />
<br />
=Bitwise Operations=<br />
<br />
==bin:or==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:or(<br />
$a as xs:base64Binary?,<br />
$b as xs:base64Binary?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the "bitwise or" of two binary arguments.<br/>If either argument is the empty sequence, an empty sequence is returned.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|differing-length-arguments|#Errors}} the input arguments are of differing length.<br />
|}<br />
<br />
==bin:xor==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:xor(<br />
$a as xs:base64Binary?,<br />
$b as xs:base64Binary?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the "bitwise xor" of two binary arguments.<br/>If either argument is the empty sequence, an empty sequence is returned.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|differing-length-arguments|#Errors}} the input arguments are of differing length.<br />
|}<br />
<br />
==bin:and==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:and(<br />
$a as xs:base64Binary?,<br />
$b as xs:base64Binary?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the "bitwise and" of two binary arguments.<br/>If either argument is the empty sequence, an empty sequence is returned.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|differing-length-arguments|#Errors}} the input arguments are of differing length.<br />
|}<br />
<br />
==bin:not==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:not(<br />
$in as xs:base64Binary?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the "bitwise not" of a binary argument.<br/>If the argument is the empty sequence, an empty sequence is returned.<br />
|}<br />
<br />
==bin:shift==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:shift(<br />
$in as xs:base64Binary?,<br />
$by as xs:integer<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Shifts bits in binary data.<br/>If {{Code|$by}} is zero, the result is identical to {{Code|$in}}. If {{Code|$by}} is positive then bits are shifted to the left. Otherwise, bits are shifted to the right. If the absolute value of <code>$by</code> is greater than the bit-length of {{Code|$in}} then an all-zeros result is returned. The result always has the same size as {{Code|$in}}. The shifting is logical: zeros are placed into discarded bits. If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|}<br />
<br />
=Errors=<br />
<br />
{| class="wikitable" width="100%"<br />
! width="240"|Code<br />
|Description<br />
|- valign="top"<br />
|{{Code|differing-length-arguments}} <br />
|The arguments to a bitwise operation have different lengths.<br />
|- valign="top"<br />
|{{Code|index-out-of-range}}<br />
|An offset value is out of range.<br />
|- valign="top"<br />
|{{Code|negative-size}}<br />
|A size value is negative.<br />
|- valign="top"<br />
|{{Code|octet-out-of-range}}<br />
|An octet value lies outside the range 0-255.<br />
|- valign="top"<br />
|{{Code|non-numeric-character}}<br />
|Binary data cannot be parsed as number.<br />
|- valign="top"<br />
|{{Code|unknown-encoding}}<br />
|An encoding is not supported.<br />
|- valign="top"<br />
|{{Code|conversion-error}}<br />
|An error or malformed input during converting a string.<br />
|- valign="top"<br />
|{{Code|unknown-significance-order}}<br />
|An octet-order value is unknown.<br />
|}<br />
<br />
=Changelog=<br />
<br />
Introduced with Version 7.8.</div>Andy Buncehttps://docs.basex.org/index.php?title=Binary_Module&diff=16616Binary Module2023-08-16T13:25:40Z<p>Andy Bunce: bin:encode-string 2nd arg optional see http://expath.org/spec/binary#encode-string</p>
<hr />
<div>This [[Module Library|XQuery Module]] contains functions to process binary data, including extracting subparts, searching, basic binary operations and conversion between binary and structured forms.<br />
<br />
This module is based on the [http://expath.org/spec/binary EXPath Binary Module].<br />
<br />
=Conventions=<br />
<br />
All functions and errors in this module are assigned to the <code><nowiki>http://expath.org/ns/binary</nowiki></code> namespace, which is statically bound to the {{Code|bin}} prefix.<br/><br />
<br />
=Constants and Conversions=<br />
<br />
==bin:hex==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:hex(<br />
$in as xs:string?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the binary form of the set of octets written as a sequence of (ASCII) hex digits ([0-9A-Fa-f]).<br/>{{Code|$in}} will be effectively zero-padded from the left to generate an integral number of octets, i.e. an even number of hexadecimal digits. If {{Code|$in}} is an empty string, then the result will be an {{Code|xs:base64Binary}} with no embedded data. Byte order in the result follows (per-octet) character order in the string. If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|non-numeric-character|#Errors}} the input cannot be parsed as a hexadecimal number.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<code>string(bin:hex('11223F4E'))</code> yields <code>ESI/Tg==</code>.<br/><code>string(xs:hexBinary(bin:hex('FF')))</code> yields <code>FF</code>.<br />
|}<br />
<br />
==bin:bin==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:bin(<br />
$in as xs:string?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the binary form of the set of octets written as a sequence of (8-wise) (ASCII) binary digits ([01]).<br/><code>$in</code> will be effectively zero-padded from the left to generate an integral number of octets. If <code>$in</code> is an empty string, then the result will be an <code>xs:base64Binary</code> with no embedded data. Byte order in the result follows (per-octet) character order in the string. If the value of <code>$in</code> is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|non-numeric-character|#Errors}} the input cannot be parsed as a binary number.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<code>string(bin:bin('1101000111010101'))</code> yields <code>0dU=</code>.<br/><code>string(xs:hexBinary(bin:bin('1000111010101')))</code> yields <code>11D5</code>.<br />
|}<br />
<br />
==bin:octal==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:octal(<br />
$in as xs:string?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the binary form of the set of octets written as a sequence of (ASCII) octal digits ([0-7]).<br/><code>$in</code> will be effectively zero-padded from the left to generate an integral number of octets. If <code>$in</code> is an empty string, then the result will be an <code>xs:base64Binary</code> with no embedded data. Byte order in the result follows (per-octet) character order in the string. If the value of <code>$in</code> is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|non-numeric-character|#Errors}} the input cannot be parsed as an octal number.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<code>string(xs:hexBinary(bin:octal('11223047')))</code> yields <code>252627</code>.<br />
|}<br />
<br />
==bin:to-octets==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:to-octets(<br />
$in as xs:base64Binary<br />
) as xs:integer*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns binary data as a sequence of octets.<br/>If <code>$in</code> is a zero length binary data then the empty sequence is returned. Octets are returned as integers from 0 to 255.<br />
|}<br />
<br />
==bin:from-octets==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:from-octets(<br />
$in as xs:integer*<br />
) as xs:base64Binary</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Converts a sequence of octets into binary data.<br/>Octets are integers from 0 to 255. If the value of <code>$in</code> is the empty sequence, the function returns zero-sized binary data.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|octet-out-of-range|#Errors}} one of the octets lies outside the range 0 - 255.<br />
|}<br />
<br />
=Basic Operations=<br />
<br />
==bin:length==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:length(<br />
$in as xs:base64Binary<br />
) as xs:integer</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the size of binary data in octets.<br />
|}<br />
<br />
==bin:part==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:part(<br />
$in as xs:base64Binary?,<br />
$offset as xs:integer,<br />
$size as xs:integer := ()<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns a section of binary data starting at the {{Code|$offset}} octet.<br/>If {{Code|$size}} is specified, the size of the returned binary data is {{Code|$size}} octets. If {{Code|$size}} is absent, all remaining data from {{Code|$offset}} is returned. The {{Code|$offset}} is zero based. If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|negative-size|#Errors}} the specified size is negative.<br/>{{Error|index-out-of-range|#Errors}} the specified offset + size is out of range.<br />
|- valign="top"<br />
| '''Examples'''<br />
|Test whether binary data starts with binary content consistent with a PDF file:<br/><code>bin:part($data, 0, 4) eq bin:hex("25504446")</code>.<br />
|}<br />
<br />
==bin:join==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:join(<br />
$in as xs:base64Binary*<br />
) as xs:base64Binary</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns an {{Code|xs:base64Binary}} created by concatenating the items in the sequence {{Code|$in}}, in order. If the value of {{Code|$in}} is the empty sequence, the function returns a binary item containing no data bytes.<br />
|}<br />
<br />
==bin:insert-before==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:insert-before(<br />
$in as xs:base64Binary?,<br />
$offset as xs:integer,<br />
$extra as xs:base64Binary?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns binary data consisting sequentially of the data from {{Code|$in}} up to and including the {{Code|$offset - 1}} octet, followed by all the data from {{Code|$extra}}, and then the remaining data from {{Code|$in}}.<br/>The {{Code|$offset}} is zero based. If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|index-out-of-range|#Errors}} the specified offset is out of range.<br />
|}<br />
<br />
==bin:pad-left==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:pad-left(<br />
$in as xs:base64Binary?,<br />
$size as xs:integer,<br />
$octet as xs:integer := ()<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns an {{Code|xs:base64Binary}} created by padding the input with {{Code|$size}} octets in front of the input. If {{Code|$octet}} is specified, the padding octets each have that value, otherwise they are zero.<br/>If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|negative-size|#Errors}} the specified size is negative.<br/>{{Error|octet-out-of-range|#Errors}} the specified octet lies outside the range 0-255.<br />
|}<br />
<br />
==bin:pad-right==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:pad-right(<br />
$in as xs:base64Binary?,<br />
$size as xs:integer,<br />
$octet as xs:integer := ()<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns an {{Code|xs:base64Binary}} created by padding the input with {{Code|$size}} octets after the input. If {{Code|$octet}} is specified, the padding octets each have that value, otherwise they are zero.<br/>If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|negative-size|#Errors}} the specified size is negative.<br/>{{Error|octet-out-of-range|#Errors}} the specified octet lies outside the range 0-255.<br />
|}<br />
<br />
==bin:find==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:find(<br />
$in as xs:base64Binary?,<br />
$offset as xs:integer,<br />
$search as xs:base64Binary<br />
) as xs:integer?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the first location of the binary search sequence in the input, or if not found, the empty sequence.<br/>The {{Code|$offset}} and the returned location are zero based. If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|index-out-of-range|#Errors}} the specified offset + size is out of range.<br />
|}<br />
<br />
=Text Decoding and Encoding=<br />
<br />
==bin:decode-string==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:decode-string(<br />
$in as xs:base64Binary?,<br />
$encoding as xs:string,<br />
$offset as xs:integer := (),<br />
$size as xs:integer := ()<br />
) as xs:string?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Decodes binary data as a string in a given {{Code|$encoding}}.<br/>If {{Code|$offset}} and {{Code|$size}} are provided, the {{Code|$size}} octets from {{Code|$offset}} are decoded. If {{Code|$offset}} alone is provided, octets from {{Code|$offset}} to the end are decoded.If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|negative-size|#Errors}} the specified size is negative.<br/>{{Error|index-out-of-range|#Errors}} the specified offset + size is out of range.<br/>{{Error|unknown-encoding|#Errors}} the specified encoding is unknown.<br/>{{Error|conversion-error|#Errors}} an error or malformed input occurred during decoding the string.<br />
|- valign="top"<br />
| '''Examples'''<br />
|Tests whether the binary data starts with binary content consistent with a PDF file:<br/><code>bin:decode-string($data, 'UTF-8', 0, 4) eq '%PDF'</code>.<br />
|}<br />
<br />
==bin:encode-string==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:encode-string(<br />
$in as xs:string?,<br />
$encoding as xs:string := 'utf-8'<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Encodes a string into binary data using a given {{Code|$encoding}}.<br/>If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|unknown-encoding|#Errors}} the specified encoding is unknown.<br/>{{Error|conversion-error|#Errors}} an error or malformed input occurred during encoding the string.<br />
|}<br />
<br />
=Packing and Unpacking of Numeric Values=<br />
<br />
The functions have an optional parameter $octet-order whose string value controls the order: Least-significant-first order is indicated by any of the values {{Code|least-significant-first}}, {{Code|little-endian}}, or {{Code|LE}}. Most-significant-first order is indicated by any of the values {{Code|most-significant-first}}, {{Code|big-endian}}, or {{Code|BE}}.<br />
<br />
==bin:pack-double==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:pack-double(<br />
$in as xs:double,<br />
$octet-order as xs:string := ()<br />
) as xs:base64Binary</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the 8-octet binary representation of a double value.<br/>Most-significant-octet-first number representation is assumed unless the {{Code|$octet-order}} parameter is specified.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|unknown-significance-order|#Errors}} the specified octet order is unknown.<br />
|}<br />
<br />
==bin:pack-float==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:pack-float(<br />
$in as xs:float,<br />
$octet-order as xs:string := ()<br />
) as xs:base64Binary</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the 4-octet binary representation of a float value.<br/>Most-significant-octet-first number representation is assumed unless the {{Code|$octet-order}} parameter is specified.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|unknown-significance-order|#Errors}} the specified octet order is unknown.<br />
|}<br />
<br />
==bin:pack-integer==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:pack-integer(<br />
$in as xs:integer,<br />
$size as xs:integer,<br />
$octet-order as xs:string := ()<br />
) as xs:base64Binary</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the twos-complement binary representation of an integer value treated as {{Code|$size}} octets long. Any 'excess' high-order bits are discarded.<br/>Most-significant-octet-first number representation is assumed unless the {{Code|$octet-order}} parameter is specified. Specifying a {{Code|$size}} of zero yields an empty binary data.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|unknown-significance-order|#Errors}} the specified octet order is unknown.<br/>{{Error|negative-size|#Errors}} the specified size is negative.<br/><br />
|}<br />
<br />
==bin:unpack-double==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:unpack-double(<br />
$in as xs:base64Binary,<br />
$offset as xs:integer,<br />
$octet-order as xs:string := ()<br />
) as xs:double</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Extracts the double value stored at the particular offset in binary data.<br/>Most-significant-octet-first number representation is assumed unless the {{Code|$octet-order}} parameter is specified. The {{Code|$offset}} is zero based.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|index-out-of-range|#Errors}} the specified offset is out of range.<br/>{{Error|unknown-significance-order|#Errors}} the specified octet order is unknown.<br />
|}<br />
<br />
==bin:unpack-float==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:unpack-float(<br />
$in as xs:base64Binary,<br />
$offset as xs:integer,<br />
$octet-order as xs:string := ()<br />
) as xs:float</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Extracts the float value stored at the particular offset in binary data.<br/>Most-significant-octet-first number representation is assumed unless the {{Code|$octet-order}} parameter is specified. The {{Code|$offset}} is zero based.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|index-out-of-range|#Errors}} the specified offset + size is out of range.<br/>{{Error|unknown-significance-order|#Errors}} the specified octet order is unknown.<br />
|}<br />
<br />
==bin:unpack-integer==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:unpack-integer(<br />
$in as xs:base64Binary,<br />
$offset as xs:integer,<br />
$size as xs:integer,<br />
$octet-order as xs:string := ()<br />
) as xs:integer</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns a signed integer value represented by the {{Code|$size}} octets starting from {{Code|$offset}} in the input binary representation. Necessary sign extension is performed (i.e. the result is negative if the high order bit is '1').<br/>Most-significant-octet-first number representation is assumed unless the {{Code|$octet-order}} parameter is specified. The {{Code|$offset}} is zero based. Specifying a {{Code|$size}} of zero yields the integer {{Code|0}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|negative-size|#Errors}} the specified size is negative.<br/>{{Error|index-out-of-range|#Errors}} the specified offset + size is out of range.<br/>{{Error|unknown-significance-order|#Errors}} the specified octet order is unknown.<br />
|}<br />
<br />
==bin:unpack-unsigned-integer==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:unpack-unsigned-integer(<br />
$in as xs:base64Binary,<br />
$offset as xs:integer,<br />
$size as xs:integer,<br />
$octet-order as xs:string := ()<br />
) as xs:integer</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns an unsigned integer value represented by the {{Code|$size}} octets starting from {{Code|$offset}} in the input binary representation.<br/>Most-significant-octet-first number representation is assumed unless the {{Code|$octet-order}} parameter is specified. The {{Code|$offset}} is zero based. Specifying a {{Code|$size}} of zero yields the integer {{Code|0}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|negative-size|#Errors}} the specified size is negative.<br/>{{Error|index-out-of-range|#Errors}} the specified offset + size is out of range.<br/>{{Error|unknown-significance-order|#Errors}} the specified octet order is unknown.<br />
|}<br />
<br />
=Bitwise Operations=<br />
<br />
==bin:or==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:or(<br />
$a as xs:base64Binary?,<br />
$b as xs:base64Binary?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the "bitwise or" of two binary arguments.<br/>If either argument is the empty sequence, an empty sequence is returned.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|differing-length-arguments|#Errors}} the input arguments are of differing length.<br />
|}<br />
<br />
==bin:xor==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:xor(<br />
$a as xs:base64Binary?,<br />
$b as xs:base64Binary?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the "bitwise xor" of two binary arguments.<br/>If either argument is the empty sequence, an empty sequence is returned.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|differing-length-arguments|#Errors}} the input arguments are of differing length.<br />
|}<br />
<br />
==bin:and==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:and(<br />
$a as xs:base64Binary?,<br />
$b as xs:base64Binary?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the "bitwise and" of two binary arguments.<br/>If either argument is the empty sequence, an empty sequence is returned.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|differing-length-arguments|#Errors}} the input arguments are of differing length.<br />
|}<br />
<br />
==bin:not==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:not(<br />
$in as xs:base64Binary?<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the "bitwise not" of a binary argument.<br/>If the argument is the empty sequence, an empty sequence is returned.<br />
|}<br />
<br />
==bin:shift==<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>bin:shift(<br />
$in as xs:base64Binary?,<br />
$by as xs:integer<br />
) as xs:base64Binary?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Shifts bits in binary data.<br/>If {{Code|$by}} is zero, the result is identical to {{Code|$in}}. If {{Code|$by}} is positive then bits are shifted to the left. Otherwise, bits are shifted to the right. If the absolute value of <code>$by</code> is greater than the bit-length of {{Code|$in}} then an all-zeros result is returned. The result always has the same size as {{Code|$in}}. The shifting is logical: zeros are placed into discarded bits. If the value of {{Code|$in}} is the empty sequence, the function returns an empty sequence.<br />
|}<br />
<br />
=Errors=<br />
<br />
{| class="wikitable" width="100%"<br />
! width="240"|Code<br />
|Description<br />
|- valign="top"<br />
|{{Code|differing-length-arguments}} <br />
|The arguments to a bitwise operation have different lengths.<br />
|- valign="top"<br />
|{{Code|index-out-of-range}}<br />
|An offset value is out of range.<br />
|- valign="top"<br />
|{{Code|negative-size}}<br />
|A size value is negative.<br />
|- valign="top"<br />
|{{Code|octet-out-of-range}}<br />
|An octet value lies outside the range 0-255.<br />
|- valign="top"<br />
|{{Code|non-numeric-character}}<br />
|Binary data cannot be parsed as number.<br />
|- valign="top"<br />
|{{Code|unknown-encoding}}<br />
|An encoding is not supported.<br />
|- valign="top"<br />
|{{Code|conversion-error}}<br />
|An error or malformed input during converting a string.<br />
|- valign="top"<br />
|{{Code|unknown-significance-order}}<br />
|An octet-order value is unknown.<br />
|}<br />
<br />
=Changelog=<br />
<br />
Introduced with Version 7.8.</div>Andy Buncehttps://docs.basex.org/index.php?title=BaseX_10&diff=16579BaseX 102023-07-05T15:42:40Z<p>Andy Bunce: Add note on boundary-space preserve</p>
<hr />
<div>After 15 years of continuous development, the first double-digit version of BaseX sees the light of day.<br />
<br />
We have taken the version jump as an opportunity to perform some major refactorings of BaseX, both under the hood and on API and XQuery level. Before migrating your projects to the new version, some adjustments may be required, so please read this article carefully.<br />
<br />
=Prerequisites=<br />
<br />
BaseX 10 requires Java 11 or later to run. Databases created with the new version are backward compatible and can still be opened with BaseX 9.<br />
<br />
=Migrating Applications=<br />
<br />
The following modifications might be relevant when migrating existing applications:<br />
<br />
* The default ports for web applications have been changed from 8984/8985 to 8080/8081.<br />
* The default admin password has been removed. The {{Code|admin}} user can only be used if a password has been assigned, e.g., via the {{Command|PASSWORD}} command.<br />
* The conventions for functions in [[Clients]] in other programming languages were revised.<br />
* The <code>IGNOREHOSTNAME</code> option was dropped and merged with {{Option|IGNORECERT}}.<br />
<br />
=Storage=<br />
<br />
==Whitespaces==<br />
<br />
All whitespaces are now preserved when importing XML resources, unless whitespace stripping is enabled.<br />
<br />
The notorious {{Code|CHOP}} option was removed to prevent conflicting behavior caused by earlier installations. It was replaced by a new {{Option|STRIPWS}} option, which defaults to {{Code|false}}. In addition, the new default of the [[Serialization|serialization parameter]] {{Code|indent}} is {{Code|no}}.<br />
<br />
Please be warned that the new default can throw off existing applications. If you want to restore the old behavior, you should assign the following values in your [[Configuration|.basex configuration file]], or the {{Code|web.xml}} file of your [[Web Application]]:<br />
<br />
<syntaxhighlight lang="xquery"><br />
STRIPWS: true<br />
SERIALIZER: indent=yes<br />
</syntaxhighlight><br />
<br />
In the GUI editor, a [[Shortcuts#Editor Shortcuts|shortcut]] and an icon were added to switch result indentation on and off.<br />
<br />
In addition, databases may considerably increase in size, as whitespaces used for indenting an XML document will be interpreted and stored as additional text nodes. If your XML resources are structured and have no [[Full-Text#Mixed Content|mixed content]], it is advisable to enable whitespaces stripping when importing them to a database.<br />
<br />
Note {{Option|STRIPWS}} only applies to stored XML and not to XML constructed within XQuery source files. Within XQuery sources the standard {{Code|boundary-space}} setting applies. This defaults to {{Code|strip}}. To preserve XML whitespace in XQuery source add the following to the prolog:<br />
<syntaxhighlight lang="xquery"><br />
declare boundary-space preserve; <br />
</syntaxhighlight><br />
==Value Resources==<br />
<br />
In addition to XML and binary resources, a third resource type has been added: XQuery values (atomic items and nodes, sequences, maps, arrays) can now be stored in databases as well. The {{Function|Database|db:put-value}} and {{Function|Database|db:get-value}} can be used to store to and retrieve values.<br />
<br />
The new feature can e.g. be used to store maps in a database:<br />
<br />
<syntaxhighlight lang="xquery"><br />
db:put-value(<br />
'factbook',<br />
map:merge(<br />
for $country in db:get('factbook')//country<br />
return map:entry($country/@name, $country//city/name ! string())<br />
),<br />
'cities'<br />
)<br />
</syntaxhighlight><br />
<br />
…and use them as index later on:<br />
<br />
<syntaxhighlight lang="xquery"><br />
let $cities := db:get-value('factbook', 'cities')<br />
for $country in ('Japan', 'Indonesia', 'Malaysia')<br />
return $country || ': ' || string-join($cities?($country), ', ')<br />
</syntaxhighlight><br />
<br />
==Backups==<br />
<br />
The [[Commands#Backups|Backup Commands]] and [[Database_Module#Backups|Backup Functions]] were enhanced to back up general data: [[User Management|registered users]], [[Job Module#Services|scheduled services]], [[Store Module|key-value stores]].<br />
<br />
=XQuery=<br />
<br />
==Compilation==<br />
<br />
The compilation has been split up into multiple steps to improve locking.<br />
<br />
So far, several internal steps were already performed when executing a query (see [[XQuery Optimizations#Introduction|XQuery Optimizations]] for more details):<br />
<br />
# The query is parsed, i.e., the original query string is transformed to an executable tree representation.<br />
# External values that are passed on by APIs are bound to variables and the query context. External values can be names of databases, or contribute to a name that will later on be constructed in the query.<br />
# The query is compiled and evaluated.<br />
<br />
The [[Transaction_Management|transaction manager]] gathers the names of the databases that will be accessed by a query. If it is not possible to uniquely identify all databases that may be opened by the query, global locking will be applied, and all databases will be locked. Detection can fail if the names of databases depend on external input. It can also fail if a query is too complex to associate character strings with database operations.<br />
<br />
The compilation phase now comprises two separate steps:<br />
<br />
# ''Compilation'' of logical, context-independent (static) operations. External values are bound to the query, and deterministic code is rewritten, simplified and pre-evaluated.<br />
# ''Optimization'' of physical, context-based (dynamic) operations. Databases are opened and checked for available indexes; current date/time is retrieved. The resulting code is further rewritten and optimized.<br />
<br />
Lock detection will be performed after the first step, and the code resulting from this step offers much more insight into which specific databases need to be locked. As a result, local locks can be applied to many more queries than before, and many queries can now run in parallel. An example:<br />
<br />
<syntaxhighlight lang="xquery"><br />
declare variable $n external;<br />
db:get('names-' || $n)<br />
</syntaxhighlight><br />
<br />
After the query has been parsed, a user-specific value (e.g., {{Code|123}}) will be bound to {{Code|$n}}. The variable will be inlined by the compiler, and the argument of {{Function||db:get}} will be pre-evaluated to {{Code|names123}}. It is then easy for the lock detector to collect the name of the database that needs to read-locked before the query is eventually executed.<br />
<br />
Another positive side effect of two-step compilation is that productive environments get faster in general: Queries can be compiled in parallel, and it’s only the optimization and evaluation of a query that may need to be delayed by locking.<br />
<br />
==Main-Memory Updates==<br />
<br />
XQuery Update provides constructs to [[XQuery Update#Main-Memory Updates|update XML nodes in main memory]]. The data structures for in-memory representations of XML resources have been revised, such that updates can be performed orders of magnitudes faster than before. With BaseX 9.x, the following query runs for several minutes, whereas it can now be computed in a few seconds:<br />
<br />
<syntaxhighlight lang="xquery"><br />
<xml>{<br />
(1 to 1000000) ! <child/><br />
}</xml> update {<br />
for $child at $pos in child<br />
return insert node text { $pos } into $child<br />
}<br />
</syntaxhighlight><br />
<br />
==Key-Value Store==<br />
<br />
A new [[Store Module]] provides functions to organize values in a persistent main-memory key-value store. The store allows you to speed up access to frequently accessed data.<br />
<br />
; Store data:<br />
<br />
<syntaxhighlight lang="xquery"><br />
let $email := map:merge(<br />
for $address in db:get('addressbook')//address<br />
return map:entry($address/name, $address/email)<br />
)<br />
return store:put('emails', $email)<br />
</syntaxhighlight><br />
<br />
; Retrieve data:<br />
<br />
<syntaxhighlight lang="xquery"><br />
let $name := 'Richard David James'<br />
return store:get('email')($name)<br />
</syntaxhighlight><br />
<br />
The store is persistent: Its contents are written to disk if BaseX is shut down, and retrieved again after a restart.<br />
<br />
==Modules==<br />
<br />
Functions of all modules, excluding the [[File Module]], now consistently resolve relative URI references against the static base URI, and not the current working directory.<br />
<br />
Various modules and functions have been revised, added, renamed or removed:<br />
<br />
{| class="wikitable"<br />
|-<br />
! Description<br />
! BaseX 10<br />
! BaseX 9<br />
|-<br />
| Retrieve XML resources<br />
| {{Function|Database|db:get}}<br />
| {{Code|db:open}}<br />
|-<br />
| Retrieve nodes with specified pre values<br />
| {{Function|Database|db:get-pre}}<br />
| {{Code|db:open-pre}}<br />
|-<br />
| Retrieve nodes with specified IDs<br />
| {{Function|Database|db:get-id}}<br />
| {{Code|db:open-id}}<br />
|-<br />
| Retrieve binary resources<br />
| {{Function|Database|db:get-binary}}<br />
| {{Code|db:retrieve}}<br />
|-<br />
| Retrieve value resources<br />
| {{Function|Database|db:get-value}}<br />
| ''new''<br />
|-<br />
| Add or replace resource<br />
| {{Function|Database|db:put}}, arguments swapped!<br />
| {{Code|db:replace}}<br />
|-<br />
| Add or replace binary resource<br />
| {{Function|Database|db:put-binary}}, arguments swapped!<br />
| {{Code|db:store}}<br />
|-<br />
| Add or replace value resource<br />
| {{Function|Database|db:put-value}}<br />
| ''new''<br />
|-<br />
| Get resource type<br />
| {{Function|Database|db:type}}<br />
| {{Code|db:is-raw}}, {{Code|db:is-xml}}<br />
|-<br />
| Fetch XML document<br />
| {{Function|Fetch|fetch:doc}}<br />
| {{Code|fetch:xml}}<br />
|-<br />
| Convert binary data to XML<br />
| {{Function|Fetch|fetch:binary-doc}}<br />
| {{Code|fetch:xml-binary}}<br />
|-<br />
| Module: Process Geo data<br />
| ''removed''<br />
| Geo Module<br />
|-<br />
| XQuery jobs<br />
| [[Job Module]]<br />
| Jobs Module<br />
|-<br />
| Return variable bindings of a job<br />
| {{Function|Job|job:bindings}}<br />
| ''new''<br />
|-<br />
| Return variable bindings of a job<br />
| {{Function|Job|job:remove}}<br />
| {{Code|jobs:stop}}<br />
|-<br />
| Module: Main-memory key-value store<br />
| [[Store Module]]<br />
| ''new''<br />
|-<br />
| Module: String computations<br />
| [[String Module]]<br />
| Strings Module<br />
|-<br />
| Format string<br />
| {{Function|String|string:format}}<br />
| {{Code|out:format}}<br />
|-<br />
| Return control characters<br />
| {{Function|String|string:cr}}, {{Function|String|string:nl}}, {{Function|String|string:tab}}<br />
| {{Code|out:cr}}, {{Code|out:nl}}, {{Code|out:tab}}<br />
|-<br />
| Module: Process ZIP files<br />
| ''removed''<br />
| ZIP Module<br />
|}<br />
<br />
=Commands=<br />
<br />
The following commands have been revised:<br />
<br />
{| class="wikitable"<br />
|-<br />
! Description<br />
! BaseX 10<br />
! BaseX 9<br />
|-<br />
| List directories and resources.<br />
| {{Command|DIR}}<br />
| ''new''<br />
|-<br />
| Retrieve single XML document<br />
| {{Command|GET}}<br />
| ''new''<br />
|-<br />
| Retrieve binary resource<br />
| {{Command|BINARY GET}}<br />
| {{Code|RETRIEVE}}<br />
|-<br />
| Add or replace resources<br />
| {{Command|PUT}}<br />
| {{Code|REPLACE}}<br />
|-<br />
| Store binary resource<br />
| {{Command|BINARY PUT}}<br />
| {{Code|STORE}}<br />
|-<br />
| Returns current option values<br />
| {{Command|SHOW OPTIONS}}<br />
| {{Code|GET}}<br />
|-<br />
| Lists jobs<br />
| ''removed''<br />
| {{Command|JOBS LIST}}<br />
|-<br />
| Returns a job result<br />
| ''removed''<br />
| {{Command|JOBS RESULT}}<br />
|-<br />
| Stops a job<br />
| ''removed''<br />
| {{Command|JOBS STOP}}<br />
|}<br />
<br />
=HTTP Requests=<br />
<br />
HTTP requests in BaseX are now based on the new [https://openjdk.org/groups/net/httpclient/intro.html Java HTTP Client]. This client provides a better overall performance, uses internal connection pools and follows redirects across different protocols (http, https).<br />
<br />
HTTP operations are, among others, performed by:<br />
<br />
* the [[HTTP Client Module]];<br />
* the [[Fetch Module]], [[Database Module]], [[Fetch Module]], [[Validation Module]], [[XSLT Module]] or [[Repository Module]];<br />
* <code>fn:doc</code> and <code>fn:collection</code>;<br />
* the {{Command|CREATE DB}} and {{Command|REPO INSTALL}} commands.<br />
<br />
=Catalogs=<br />
<br />
From early on, catalog resolvers had been neglected both in BaseX and Java. This has changed: The new [https://docs.oracle.com/en/java/javase/11/core/xml-catalog-api1.html XML Catalog API] from Java is universally used to resolve references to external resources. As an alternative, Norman Walsh’s [https://xmlresolver.org/ Enhanced XML Resolver] is utilized if it is found in the classpath. <br />
<br />
The option for supplying the XML catalog was renamed from <code>CATFILE</code> to {{Option|CATALOG}}. See [[Catalog Resolver]] for more details.<br />
<br />
=Graphical User Interface=<br />
<br />
The graphical user interface of BaseX has been revised and made more consistent.<br />
<br />
The icons were replaced by scalable ones, building upon the [https://openjdk.org/jeps/263 HiDPI graphics support for Windows and Linux].<br />
<br />
=REST=<br />
<br />
Results in the {{Code|rest}} namespace are now returned without prefix:<br />
<br />
<syntaxhighlight lang="xml"><br />
<!-- before --><br />
<rest:databases xmlns:rest="http://basex.org/rest"/><br />
<br />
<!-- now --><br />
<databases xmlns="http://basex.org/rest"/><br />
</syntaxhighlight><br />
<br />
When listing the resources of a database, {{Code|dir}} elements are returned for resources that are located in subdirectories. See [[REST]] for more details.</div>Andy Buncehttps://docs.basex.org/index.php?title=Array_Module&diff=16577Array Module2023-07-03T14:34:18Z<p>Andy Bunce: remove no-break-space</p>
<hr />
<div>This [[Module Library|XQuery Module]] contains functions for manipulating arrays, which has been introduced with [[XQuery 3.1#Arrays|XQuery 3.1]].<br />
<br />
=Conventions=<br />
<br />
All functions and errors in this module are assigned to the <code><nowiki>http://www.w3.org/2005/xpath-functions/array</nowiki></code> namespace, which is statically bound to the {{Code|array}} prefix.<br/><br />
<br />
=Functions=<br />
<br />
==array:size==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:size(<br />
$array as array(*)<br />
) as xs:integer</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns the number of members in {{Code|$array}}. Note that because an array is an item, the {{Code|fn:count}} function when applied to an array always returns {{Code|1}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:size(array { 1 to 10 })</code> returns {{Code|10}}.<br />
* <code>array:size([1 to 10])</code> returns {{Code|1}}, because the array contains a single sequence with 10 integers.<br />
|}<br />
<br />
==array:get==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:get(<br />
$array as array(*),<br />
$position as xs:integer<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns the {{Code|$array}} member at the specified {{Code|$position}}. <br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} {{Code|$position}} is not in the range {{Code|1}} to {{Code|array:size($array)}} inclusive.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:get(array { reverse(1 to 5) }, 5)</code> returns the value {{Code|1}}.<br />
|}<br />
<br />
==array:append==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:append(<br />
$array as array(*),<br />
$member as item()*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a copy of {{Code|$array}} with {{Code|$member}} attached.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:append([], 'member1')</code> returns the array {{Code|["member1"]}}.<br />
|}<br />
<br />
==array:subarray==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:subarray(<br />
$array as array(*),<br />
$position as xs:integer,<br />
$length as xs:integer := ()<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Constructs a new array with with {{Code|$length}} members of {{Code|$array}} beginning from the specified {{Code|$position}}.<br/>The two-argument version of the function returns the same result as the three-argument version when called with {{Code|$length}} equal to the value of {{Code|array:size($array) - $position + 1}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} {{Code|$position}} is less than one, or if {{Code|$position + $length}} is greater than {{Code|array:size($array) + 1}}.<br/>{{Error|FOAY0002|#Errors}} {{Code|$length}} is less than zero.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:subarray(["a", "b", "c"], 2)</code> returns the array {{Code|["b", "c"]}}.<br />
|}<br />
<br />
==array:put==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:put(<br />
$array as array(*),<br />
$position as xs:integer,<br />
$member as item()*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a copy of {{Code|$array}} with {{Code|$member}} replaced at the specified {{Code|$position}}. Equivalent to <code>$array => array:remove($position) => array:insert-before($position, $member)</code>.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} {{Code|$position}} is not in the range {{Code|1}} to {{Code|array:size($array)}} inclusive.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:put(["a", "b", "c"], 2, "d")</code> returns the array {{Code|["a", "d", "c"]}}.<br />
|}<br />
<br />
==array:remove==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:remove(<br />
$array as array(*),<br />
$positions as xs:integer*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a copy of {{Code|$array}} without the member at the specified {{Code|$positions}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} A position is not in the range {{Code|1}} to {{Code|array:size($array)}} inclusive.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:append(["a"], 1)</code> returns the array {{Code|[]}}.<br />
|}<br />
<br />
==array:insert-before==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:insert-before(<br />
$array as array(*),<br />
$position as xs:integer,<br />
$member as item()*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a copy of {{Code|$array}} with one new {{Code|$member}} at the specified {{Code|$position}}. Setting {{Code|$position}} to the value {{Code|array:size($array) + 1}} yields the same result as {{Code|array:append($array, $insert)}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} {{Code|$position}} is not in the range {{Code|1}} to {{Code|array:size($array) + 1}} inclusive.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:insert-before(["a"], 1, "b")</code> returns the array {{Code|["b", "a"]}}.<br />
|}<br />
<br />
==array:head==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:head(<br />
$array as array(*)<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns the first member of {{Code|$array}}. This function is equivalent to the expression {{Code|$array(1)}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} The array is empty.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:head(["a", "b"])</code> returns {{Code|"a"}}.<br />
* <code>array:head([["a", "b"], ["c", "d"]])</code> returns the array {{Code|["a", "b"]}}.<br />
|}<br />
<br />
==array:tail==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:tail(<br />
$array as array(*)<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array with all members except the first from {{Code|$array}}. This function is equivalent to the expression {{Code|array:remove($array, 1)}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} The array is empty.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:insert-before(["a"], 1, "b")</code> returns the array {{Code|["b", "a"]}}.<br />
|}<br />
<br />
==array:reverse==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:reverse(<br />
$array as array(*)<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array with all members of {{Code|$array}} in reverse order.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:reverse(array { 1 to 3 })</code> returns the array {{Code|[3, 2, 1]}}.<br />
|}<br />
<br />
==array:join==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:join(<br />
$arrays as array(*)*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Concatenates the contents of several {{Code|$arrays}} into a single array.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:join(())</code> returns the array {{Code|[]}}.<br />
* <code>array:join((1 to 3) ! array { . })</code> returns the array {{Code|[1, 2, 3]}}.<br />
|}<br />
<br />
==array:flatten==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:flatten(<br />
$items as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Recursively flattens all arrays that occur in the supplied {{Code|$items}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:flatten(["a","b"])</code> returns the sequence {{Code|"a", "b"}}.<br />
* <code>array:flatten([1,[2,3],4]])</code> returns the sequence {{Code|1, 2, 3, 4}}.<br />
|}<br />
<br />
==array:for-each==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:for-each(<br />
$array as array(*),<br />
$action as function(item()*) as item()*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array, in which each member is computed by applying {{Code|$action}} to the corresponding member of {{Code|$array}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|The following query returns the array {{Code|[2, 3, 4, 5, 6]}}:<br />
<br />
<syntaxhighlight lang="xquery"><br />
array:for-each(<br />
array { 1 to 5 },<br />
function($i) { $i + 1}<br />
)<br />
</syntaxhighlight><br />
|}<br />
<br />
==array:filter==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:filter(<br />
$array as array(*),<br />
$predicate as function(item()*) as xs:boolean<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array with those members of {{Code|$array}} for which {{Code|$predicate}} returns {{Code|true}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|The following query returns the array {{Code|[0, 1, 3]}}:<br />
<syntaxhighlight lang="xquery"><br />
array:filter(<br />
array { 0, 1, -2, 3, -4 },<br />
function($i) { $i > 0 }<br />
)<br />
</syntaxhighlight><br />
|}<br />
<br />
==array:fold-left==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:fold-left(<br />
$array as array(*),<br />
$zero as item()*,<br />
$action as function(item()*, item()*) as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Evaluates the supplied {{Code|$action}} cumulatively on successive members of the supplied {{Code|$array}} from left to right, and uses {{Code|$zero}} as first argument.<br />
|- valign="top"<br />
| '''Examples'''<br />
|The following query returns {{Code|55}} (the sum of the integers 1 to 10):<br />
<syntaxhighlight lang="xquery"><br />
array:fold-left(<br />
array { 1 to 10 },<br />
0,<br />
function($a, $b) { $a + $b }<br />
)<br />
</syntaxhighlight><br />
|}<br />
<br />
==array:fold-right==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:fold-right(<br />
$array as array(*),<br />
$zero as item()*,<br />
$action as function(item()*, item()*) as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Evaluates the supplied {{Code|$action}} cumulatively on successive members of the supplied {{Code|$array}} from right to left, and uses {{Code|$zero}} as first argument.<br />
|- valign="top"<br />
| '''Examples'''<br />
|The following query is equivalent to the expression <code>array:reverse(array { 1 to 5 })</code>:<br />
<syntaxhighlight lang="xquery"><br />
array {<br />
array:fold-right(<br />
array { 1 to 5 },<br />
(),<br />
function($a, $b) { $b, $a }<br />
)<br />
}<br />
</syntaxhighlight><br />
|}<br />
<br />
==array:for-each-pair==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:for-each-pair(<br />
$array1 as array(*),<br />
$array2 as array(*),<br />
$action as function(item()*) as item()*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array obtained by evaluating the supplied {{Code|$action}} for each pair of members at the same position in {{Code|$array1}} and {{Code|$array2}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|The following query returns the array {{Code|[5, 7, 9]}}:<br />
<syntaxhighlight lang="xquery"><br />
array:for-each-pair(<br />
array { 1 to 3 },<br />
array { 4 to 6 },<br />
function($a + $b) { $a + $b }<br />
)<br />
</syntaxhighlight><br />
|}<br />
<br />
==array:sort==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:sort(<br />
$array as array(*),<br />
$collation as xs:string? := (),<br />
$key as function(item()*) as xs:anyAtomicType*:= ()<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array with sorted {{Code|$array}} members, using an optional {{Code|$collation}}. If a {{Code|$key}} function is supplied, it will be applied on all array members. The items of the resulting values will be sorted using the semantics of the {{Code|lt}} expression.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:sort(array { reverse(1 to 3) })</code> returns <code>[1, 2, 3]</code><br />
* <code>array:sort([3,-2,1], (), abs#1)</code> returns <code>[1, -2, 3]</code><br />
* <code>array:sort([1,2,3], (), function($x) { -$x })</code> returns <code>[3, 2, 1]</code><br />
* <code>array:sort((1,'a'))</code> returns an error (strings and integers cannot be compared)<br />
|}<br />
<br />
=Errors=<br />
<br />
{| class="wikitable" width="100%"<br />
! width="110"|Code<br />
|Description<br />
|- valign="top"<br />
|{{Code|FOAY0001}}<br />
|The specified index extends beyonds the bounds of an array.<br />
|- valign="top"<br />
|{{Code|FOAY0002}}<br />
|The specified length is less than zero.<br />
|}<br />
<br />
=Changelog=<br />
<br />
;Version 8.6<br />
* Updated: {{Function||array:put}} collation argument was inserted between first and second argument.<br />
<br />
;Version 8.5<br />
* Added: {{Function||array:put}}<br />
<br />
;Version 8.4<br />
* Removed: array:serialize (use fn:serialize instead)<br />
<br />
Introduced with Version 8.0.</div>Andy Buncehttps://docs.basex.org/index.php?title=Array_Module&diff=16576Array Module2023-07-03T14:25:59Z<p>Andy Bunce: remove extra )</p>
<hr />
<div>This [[Module Library|XQuery Module]] contains functions for manipulating arrays, which has been introduced with [[XQuery 3.1#Arrays|XQuery 3.1]].<br />
<br />
=Conventions=<br />
<br />
All functions and errors in this module are assigned to the <code><nowiki>http://www.w3.org/2005/xpath-functions/array</nowiki></code> namespace, which is statically bound to the {{Code|array}} prefix.<br/><br />
<br />
=Functions=<br />
<br />
==array:size==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:size(<br />
$array as array(*)<br />
) as xs:integer</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns the number of members in {{Code|$array}}. Note that because an array is an item, the {{Code|fn:count}} function when applied to an array always returns {{Code|1}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:size(array { 1 to 10 })</code> returns {{Code|10}}.<br />
* <code>array:size([1 to 10])</code> returns {{Code|1}}, because the array contains a single sequence with 10 integers.<br />
|}<br />
<br />
==array:get==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:get(<br />
$array as array(*),<br />
$position as xs:integer<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns the {{Code|$array}} member at the specified {{Code|$position}}. <br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} {{Code|$position}} is not in the range {{Code|1}} to {{Code|array:size($array)}} inclusive.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:get(array { reverse(1 to 5) }, 5)</code> returns the value {{Code|1}}.<br />
|}<br />
<br />
==array:append==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:append(<br />
$array as array(*),<br />
$member as item()*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a copy of {{Code|$array}} with {{Code|$member}} attached.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:append([], 'member1')</code> returns the array {{Code|["member1"]}}.<br />
|}<br />
<br />
==array:subarray==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:subarray(<br />
$array as array(*),<br />
$position as xs:integer,<br />
$length as xs:integer := ()<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Constructs a new array with with {{Code|$length}} members of {{Code|$array}} beginning from the specified {{Code|$position}}.<br/>The two-argument version of the function returns the same result as the three-argument version when called with {{Code|$length}} equal to the value of {{Code|array:size($array) - $position + 1}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} {{Code|$position}} is less than one, or if {{Code|$position + $length}} is greater than {{Code|array:size($array) + 1}}.<br/>{{Error|FOAY0002|#Errors}} {{Code|$length}} is less than zero.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:subarray(["a", "b", "c"], 2)</code> returns the array {{Code|["b", "c"]}}.<br />
|}<br />
<br />
==array:put==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:put(<br />
$array as array(*),<br />
$position as xs:integer,<br />
$member as item()*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a copy of {{Code|$array}} with {{Code|$member}} replaced at the specified {{Code|$position}}. Equivalent to <code>$array => array:remove($position) => array:insert-before($position, $member)</code>.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} {{Code|$position}} is not in the range {{Code|1}} to {{Code|array:size($array)}} inclusive.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:put(["a", "b", "c"], 2, "d")</code> returns the array {{Code|["a", "d", "c"]}}.<br />
|}<br />
<br />
==array:remove==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:remove(<br />
$array as array(*),<br />
$positions as xs:integer*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a copy of {{Code|$array}} without the member at the specified {{Code|$positions}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} A position is not in the range {{Code|1}} to {{Code|array:size($array)}} inclusive.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:append(["a"], 1)</code> returns the array {{Code|[]}}.<br />
|}<br />
<br />
==array:insert-before==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:insert-before(<br />
$array as array(*),<br />
$position as xs:integer,<br />
$member as item()*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a copy of {{Code|$array}} with one new {{Code|$member}} at the specified {{Code|$position}}. Setting {{Code|$position}} to the value {{Code|array:size($array) + 1}} yields the same result as {{Code|array:append($array, $insert)}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} {{Code|$position}} is not in the range {{Code|1}} to {{Code|array:size($array) + 1}} inclusive.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:insert-before(["a"], 1, "b")</code> returns the array {{Code|["b", "a"]}}.<br />
|}<br />
<br />
==array:head==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:head(<br />
$array as array(*)<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns the first member of {{Code|$array}}. This function is equivalent to the expression {{Code|$array(1)}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} The array is empty.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:head(["a", "b"])</code> returns {{Code|"a"}}.<br />
* <code>array:head([["a", "b"], ["c", "d"]])</code> returns the array {{Code|["a", "b"]}}.<br />
|}<br />
<br />
==array:tail==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:tail(<br />
$array as array(*)<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array with all members except the first from {{Code|$array}}. This function is equivalent to the expression {{Code|array:remove($array, 1)}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} The array is empty.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:insert-before(["a"], 1, "b")</code> returns the array {{Code|["b", "a"]}}.<br />
|}<br />
<br />
==array:reverse==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:reverse(<br />
$array as array(*)<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array with all members of {{Code|$array}} in reverse order.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:reverse(array { 1 to 3 })</code> returns the array {{Code|[3, 2, 1]}}.<br />
|}<br />
<br />
==array:join==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:join(<br />
$arrays as array(*)*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Concatenates the contents of several {{Code|$arrays}} into a single array.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:join(())</code> returns the array {{Code|[]}}.<br />
* <code>array:join((1 to 3) ! array { . })</code> returns the array {{Code|[1, 2, 3]}}.<br />
|}<br />
<br />
==array:flatten==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:flatten(<br />
$items as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Recursively flattens all arrays that occur in the supplied {{Code|$items}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:flatten(["a","b"])</code> returns the sequence {{Code|"a", "b"}}.<br />
* <code>array:flatten([1,[2,3],4]])</code> returns the sequence {{Code|1, 2, 3, 4}}.<br />
|}<br />
<br />
==array:for-each==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:for-each(<br />
$array as array(*),<br />
$action as function(item()*) as item()*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array, in which each member is computed by applying {{Code|$action}} to the corresponding member of {{Code|$array}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|The following query returns the array {{Code|[2, 3, 4, 5, 6]}}:<br />
<br />
<syntaxhighlight lang="xquery"><br />
array:for-each(<br />
array { 1 to 5 },<br />
function($i) { $i + 1}<br />
)<br />
</syntaxhighlight><br />
|}<br />
<br />
==array:filter==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:filter(<br />
$array as array(*),<br />
$predicate as function(item()*) as xs:boolean<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array with those members of {{Code|$array}} for which {{Code|$predicate}} returns {{Code|true}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|The following query returns the array {{Code|[0, 1, 3]}}:<br />
<syntaxhighlight lang="xquery"><br />
array:filter(<br />
array { 0, 1, -2, 3, -4 },<br />
function($i) { $i > 0 }<br />
)<br />
</syntaxhighlight><br />
|}<br />
<br />
==array:fold-left==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:fold-left(<br />
$array as array(*),<br />
$zero as item()*,<br />
$action as function(item()*, item()*) as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Evaluates the supplied {{Code|$action}} cumulatively on successive members of the supplied {{Code|$array}} from left to right, and uses {{Code|$zero}} as first argument.<br />
|- valign="top"<br />
| '''Examples'''<br />
|The following query returns {{Code|55}} (the sum of the integers 1 to 10):<br />
<syntaxhighlight lang="xquery"><br />
array:fold-left(<br />
array { 1 to 10 },<br />
0,<br />
function($a, $b) { $a + $b }<br />
)<br />
</syntaxhighlight><br />
|}<br />
<br />
==array:fold-right==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:fold-right(<br />
$array as array(*),<br />
$zero as item()*,<br />
$action as function(item()*, item()*) as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Evaluates the supplied {{Code|$action}} cumulatively on successive members of the supplied {{Code|$array}} from right to left, and uses {{Code|$zero}} as first argument.<br />
|- valign="top"<br />
| '''Examples'''<br />
|The following query is equivalent to the expression <code>array:reverse(array { 1 to 5 })</code>:<br />
<syntaxhighlight lang="xquery"><br />
array {<br />
array:fold-right(<br />
array { 1 to 5 },<br />
(),<br />
function($a, $b) { $b, $a }<br />
)<br />
}<br />
</syntaxhighlight><br />
|}<br />
<br />
==array:for-each-pair==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:for-each-pair(<br />
$array1 as array(*),<br />
$array2 as array(*),<br />
$action as function(item()*) as item()*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array obtained by evaluating the supplied {{Code|$action}} for each pair of members at the same position in {{Code|$array1}} and {{Code|$array2}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|The following query returns the array {{Code|[5, 7, 9]}}:<br />
<syntaxhighlight lang="xquery"><br />
array:for-each-pair(<br />
array { 1 to 3 },<br />
array { 4 to 6 },<br />
function($a + $b) { $a + $b }<br />
)<br />
</syntaxhighlight><br />
|}<br />
<br />
==array:sort==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:sort(<br />
$array as array(*),<br />
$collation as xs:string? := (),<br />
$key as function(item()*) as xs:anyAtomicType* := ()<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array with sorted {{Code|$array}} members, using an optional {{Code|$collation}}. If a {{Code|$key}} function is supplied, it will be applied on all array members. The items of the resulting values will be sorted using the semantics of the {{Code|lt}} expression.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:sort(array { reverse(1 to 3) })</code> returns <code>[1, 2, 3]</code><br />
* <code>array:sort([3,-2,1], (), abs#1)</code> returns <code>[1, -2, 3]</code><br />
* <code>array:sort([1,2,3], (), function($x) { -$x })</code> returns <code>[3, 2, 1]</code><br />
* <code>array:sort((1,'a'))</code> returns an error (strings and integers cannot be compared)<br />
|}<br />
<br />
=Errors=<br />
<br />
{| class="wikitable" width="100%"<br />
! width="110"|Code<br />
|Description<br />
|- valign="top"<br />
|{{Code|FOAY0001}}<br />
|The specified index extends beyonds the bounds of an array.<br />
|- valign="top"<br />
|{{Code|FOAY0002}}<br />
|The specified length is less than zero.<br />
|}<br />
<br />
=Changelog=<br />
<br />
;Version 8.6<br />
* Updated: {{Function||array:put}} collation argument was inserted between first and second argument.<br />
<br />
;Version 8.5<br />
* Added: {{Function||array:put}}<br />
<br />
;Version 8.4<br />
* Removed: array:serialize (use fn:serialize instead)<br />
<br />
Introduced with Version 8.0.</div>Andy Buncehttps://docs.basex.org/index.php?title=Higher-Order_Functions_Module&diff=16575Higher-Order Functions Module2023-07-03T13:22:45Z<p>Andy Bunce: signatures add comma</p>
<hr />
<div>This [[Module Library|XQuery Module]] adds some useful higher-order functions, additional to the [[Higher-Order Functions]] provided by the official specification.<br />
<br />
=Conventions=<br />
<br />
All functions in this module are assigned to the <code><nowiki>http://basex.org/modules/hof</nowiki></code> namespace, which is statically bound to the {{Code|hof}} prefix.<br/><br />
<br />
=Loops=<br />
<br />
==hof:fold-left1==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>hof:fold-left1(<br />
$input as item()+,<br />
$action as function(item()*, item()) as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Works the same as [[Higher-Order Functions#fn:fold-left|fn:fold-left]], but does not need a seed, because the sequence must be non-empty.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|hof:fold-left1(1 to 10, function($a, $b) { $a + $b })}} returns {{Code|55}}.<br />
* {{Code|hof:fold-left1((), function($a, $b) { $a + $b })}} throws {{Code|XPTY0004}}, because {{Code|$seq}} has to be non-empty.<br />
|}<br />
<br />
==hof:until==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>hof:until(<br />
$predicate as function(item()*) as xs:boolean,<br />
$action as function(item()*) as item()*,<br />
$zero as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Applies the predicate function {{Code|$predicate}} to {{Code|$zero}}. If the result is {{Code|false}}, {{Code|$action}} is invoked with the start value – or, subsequently, with the result of this function – until the predicate function returns {{Code|true()}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* Doubles a numeric value until a maximum is reached:<br />
<syntaxhighlight lang="xquery"><br />
hof:until(<br />
function($output) { $output ge 1000 },<br />
function($input ) { 2 * $input },<br />
1<br />
)<br />
</syntaxhighlight><br />
* Calculates the square root of a number by iteratively improving an initial guess:<br />
<syntaxhighlight lang="xquery"><br />
let $sqrt := function($input as xs:double) as xs:double {<br />
hof:until(<br />
function($result) { abs($result * $result - $input) < 0.00001 },<br />
function($guess) { ($guess + $input div $guess) div 2 },<br />
$input<br />
)<br />
}<br />
return $sqrt(25)<br />
</syntaxhighlight><br />
* Returns {{Code|OK}}, as the predicate is evaluated first:<br />
<syntaxhighlight lang="xquery"><br />
hof:until(<br />
function($_) { true() },<br />
function($_) { error() },<br />
'OK'<br />
)<br />
</syntaxhighlight><br />
|}<br />
<br />
==hof:scan-left==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>hof:scan-left(<br />
$input as item()*,<br />
$zero as item()*,<br />
$action as function(item()*, item()) as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|This function is similar to [[Higher-Order Functions#fn:fold-left|fn:fold-left]], but it returns a list of successive reduced values from the left. It is equivalent to:<br />
<syntaxhighlight lang="xquery"><br />
declare function hof:scan-left($input, $acc, $action) {<br />
if(empty($input)) then $acc else (<br />
$acc,<br />
hof:scan-left(tail($input), $action($acc, head($input)), $action)<br />
)<br />
};<br />
</syntaxhighlight><br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* Returns triangular numbers:<br />
<syntaxhighlight lang="xquery"><br />
hof:scan-left(1 to 10, 0, function($a, $b) { $a + $b })<br />
</syntaxhighlight><br />
|}<br />
<br />
==hof:take-while==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>hof:take-while(<br />
$input as item()*,<br />
$predicate as function(item()) as xs:boolean<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|The function returns items of <code>$input</code> as long as the <code>$predicate</code> is satisfied. It is equivalent to:<br />
<syntaxhighlight lang="xquery"><br />
declare function hof:take-while($input, $predicate) {<br />
if(empty($input) or not($predicate(head($input)))) then () else (<br />
head($input),<br />
hof:take-while(tail($input), $predicate)<br />
)<br />
};<br />
</syntaxhighlight><br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* Computes at most 100 random integers, but stops if an integer is smaller than 10:<br />
<syntaxhighlight lang="xquery"><br />
hof:take-while(<br />
(1 to 100) ! random:integer(50),<br />
function($x) { $x >= 10 }<br />
)<br />
</syntaxhighlight><br />
|}<br />
<br />
==hof:drop-while==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>hof:drop-while(<br />
$input as item()*,<br />
$predicate as function(item()*) as xs:boolean<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|The function skips all items of <code>$input</code> until the <code>$predicate</code> is not satisfied anymore. It is equivalent to:<br />
<syntaxhighlight lang="xquery"><br />
declare function hof:drop-while($input, $predicate) {<br />
if($predicate(head($input))) then (<br />
hof:drop-while(tail($input), $predicate)<br />
) else (<br />
$input<br />
)<br />
};<br />
</syntaxhighlight><br />
|- valign="top"<br />
| '''Examples'''<br />
|Returns the name of the first file that does not exist on disk:<br />
<syntaxhighlight lang="xquery"><br />
hof:drop-while(<br />
(1 to 1000) ! (. || '.log'),<br />
file:exists#1<br />
)[1]<br />
</syntaxhighlight><br />
|}<br />
<br />
=Sorting=<br />
<br />
==hof:top-k-by==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>hof:top-k-by(<br />
$input as item()*,<br />
$key as function(item()) as item(),<br />
$k as xs:integer<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the {{Code|$k}} items in {{Code|$input}} that are greatest when sorted by the result of {{Code|$key}} applied to the item. The function is a much more efficient implementation of the following scheme:<br />
<syntaxhighlight lang="xquery"><br />
(for $item in $input<br />
order by $key($item) descending<br />
return $item<br />
)[position() <= $k]<br />
</syntaxhighlight><br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|hof:top-k-by(1 to 1000, hof:id#1, 5)}} returns {{Code|1000 999 998 997 996}}<br />
* {{Code|hof:top-k-by(1 to 1000, function($x) { -$x }, 3)}} returns {{Code|1 2 3}}<br />
* <code>hof:top-k-by(<x a='1' b='2' c='3'/>/@*, xs:integer#1, 2)/node-name()</code> returns {{Code|c b}}<br />
|}<br />
<br />
==hof:top-k-with==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>hof:top-k-with(<br />
$input as item()*,<br />
$comparator as function(item(), item()) as xs:boolean,<br />
$k as xs:integer<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the {{Code|$k}} items in {{Code|$input}} that are greatest when sorted in the order of the ''less-than'' predicate {{Code|$comparator}}. The function is a general version of {{Function||hof:top-k-by}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|hof:top-k-with(1 to 1000, function($a, $b) { $a lt $b }, 5)}} returns {{Code|1000 999 998 997 996}}<br />
* {{Code|hof:top-k-with(-5 to 5, function($a, $b) { abs($a) gt abs($b) }, 5)}} returns {{Code|0 1 -1 2 -2}}<br />
|}<br />
<br />
=IDs=<br />
<br />
==hof:id==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>hof:id(<br />
$input as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns its argument unchanged. This function isn’t useful on its own, but can be used as an argument to other higher-order functions.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|hof:id(1 to 5)}} returns {{Code|1 2 3 4 5}}<br />
* With higher-order functions:<br />
<syntaxhighlight lang="xquery"><br />
let $sort := sort(?, (), hof:id#1)<br />
let $reverse-sort := sort(?, (), function($x) { -$x })<br />
return (<br />
$sort((1, 5, 3, 2, 4)),<br />
'|',<br />
$reverse-sort((1, 5, 3, 2, 4))<br />
)<br />
</syntaxhighlight><br />
returns: <code>1 2 3 4 5 | 5 4 3 2 1</code><br />
|}<br />
<br />
==hof:const==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>hof:const(<br />
$input as item()*,<br />
$ignore as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns its first argument unchanged and ignores the second. This function isn’t useful on its own, but can be used as argument to other higher-order functions, e.g., when a function combining two values is expected and one only wants to retain the left one.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|hof:const(42, 1337)}} returns {{Code|42}}.<br />
* With higher-order functions:<br />
<syntaxhighlight lang="xquery"><br />
let $zip-sum := function($f, $seq1, $seq2) {<br />
sum(for-each-pair($seq1, $seq2, $f))<br />
}<br />
let $sum-all := $zip-sum(function($a, $b) { $a + $b }, ?, ?)<br />
let $sum-left := $zip-sum(hof:const#2, ?, ?)<br />
return (<br />
$sum-all((1, 1, 1, 1, 1), 1 to 5),<br />
$sum-left((1, 1, 1, 1, 1), 1 to 5)<br />
)<br />
</syntaxhighlight><br />
* Another use-case: When inserting a key into a map, {{Code|$f}} decides how to combine the new value with a possibly existing old one. {{Code|hof:const}} here means ignoring the old value, so that's normal insertion.<br />
<syntaxhighlight lang="xquery"><br />
let $insert-with := function($f, $map, $k, $v) {<br />
let $old := $map($k)<br />
let $new := if($old) then $f($v, $old) else $v<br />
return map:merge(($map, map:entry($k, $new)))<br />
}<br />
let $map := map { 'foo': 1 }<br />
let $add := $insert-with(function($a, $b) { $a + $b }, ?, ?, ?)<br />
let $ins := $insert-with(hof:const#2, ?, ?, ?)<br />
return (<br />
$add($map, 'foo', 2)('foo'),<br />
$ins($map, 'foo', 42)('foo')<br />
)<br />
</syntaxhighlight><br />
returns {{Code|3 42}}<br />
|}<br />
<br />
=Changelog=<br />
<br />
;Version 9.5<br />
* Added: {{Function||hof:drop-while}}<br />
<br />
;Version 8.1<br />
* Added: {{Function||hof:scan-left}}, {{Function||hof:take-while}}<br />
<br />
;Version 7.2<br />
* Added: {{Function||hof:top-k-by}}, {{Function||hof:top-k-with}}<br />
* Removed: hof:iterate<br />
<br />
;Version 7.0<br />
* module added</div>Andy Buncehttps://docs.basex.org/index.php?title=Array_Module&diff=16574Array Module2023-07-03T13:20:22Z<p>Andy Bunce: add return types for function args in signatures</p>
<hr />
<div>This [[Module Library|XQuery Module]] contains functions for manipulating arrays, which has been introduced with [[XQuery 3.1#Arrays|XQuery 3.1]].<br />
<br />
=Conventions=<br />
<br />
All functions and errors in this module are assigned to the <code><nowiki>http://www.w3.org/2005/xpath-functions/array</nowiki></code> namespace, which is statically bound to the {{Code|array}} prefix.<br/><br />
<br />
=Functions=<br />
<br />
==array:size==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:size(<br />
$array as array(*)<br />
) as xs:integer</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns the number of members in {{Code|$array}}. Note that because an array is an item, the {{Code|fn:count}} function when applied to an array always returns {{Code|1}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:size(array { 1 to 10 })</code> returns {{Code|10}}.<br />
* <code>array:size([1 to 10])</code> returns {{Code|1}}, because the array contains a single sequence with 10 integers.<br />
|}<br />
<br />
==array:get==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:get(<br />
$array as array(*),<br />
$position as xs:integer<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns the {{Code|$array}} member at the specified {{Code|$position}}. <br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} {{Code|$position}} is not in the range {{Code|1}} to {{Code|array:size($array)}} inclusive.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:get(array { reverse(1 to 5) }, 5)</code> returns the value {{Code|1}}.<br />
|}<br />
<br />
==array:append==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:append(<br />
$array as array(*),<br />
$member as item()*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a copy of {{Code|$array}} with {{Code|$member}} attached.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:append([], 'member1')</code> returns the array {{Code|["member1"]}}.<br />
|}<br />
<br />
==array:subarray==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:subarray(<br />
$array as array(*),<br />
$position as xs:integer,<br />
$length as xs:integer := ()<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Constructs a new array with with {{Code|$length}} members of {{Code|$array}} beginning from the specified {{Code|$position}}.<br/>The two-argument version of the function returns the same result as the three-argument version when called with {{Code|$length}} equal to the value of {{Code|array:size($array) - $position + 1}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} {{Code|$position}} is less than one, or if {{Code|$position + $length}} is greater than {{Code|array:size($array) + 1}}.<br/>{{Error|FOAY0002|#Errors}} {{Code|$length}} is less than zero.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:subarray(["a", "b", "c"], 2)</code> returns the array {{Code|["b", "c"]}}.<br />
|}<br />
<br />
==array:put==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:put(<br />
$array as array(*),<br />
$position as xs:integer,<br />
$member as item()*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a copy of {{Code|$array}} with {{Code|$member}} replaced at the specified {{Code|$position}}. Equivalent to <code>$array => array:remove($position) => array:insert-before($position, $member)</code>.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} {{Code|$position}} is not in the range {{Code|1}} to {{Code|array:size($array)}} inclusive.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:put(["a", "b", "c"], 2, "d")</code> returns the array {{Code|["a", "d", "c"]}}.<br />
|}<br />
<br />
==array:remove==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:remove(<br />
$array as array(*),<br />
$positions as xs:integer*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a copy of {{Code|$array}} without the member at the specified {{Code|$positions}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} A position is not in the range {{Code|1}} to {{Code|array:size($array)}} inclusive.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:append(["a"], 1)</code> returns the array {{Code|[]}}.<br />
|}<br />
<br />
==array:insert-before==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:insert-before(<br />
$array as array(*),<br />
$position as xs:integer,<br />
$member as item()*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a copy of {{Code|$array}} with one new {{Code|$member}} at the specified {{Code|$position}}. Setting {{Code|$position}} to the value {{Code|array:size($array) + 1}} yields the same result as {{Code|array:append($array, $insert)}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} {{Code|$position}} is not in the range {{Code|1}} to {{Code|array:size($array) + 1}} inclusive.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:insert-before(["a"], 1, "b")</code> returns the array {{Code|["b", "a"]}}.<br />
|}<br />
<br />
==array:head==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:head(<br />
$array as array(*)<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns the first member of {{Code|$array}}. This function is equivalent to the expression {{Code|$array(1)}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} The array is empty.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:head(["a", "b"])</code> returns {{Code|"a"}}.<br />
* <code>array:head([["a", "b"], ["c", "d"]])</code> returns the array {{Code|["a", "b"]}}.<br />
|}<br />
<br />
==array:tail==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:tail(<br />
$array as array(*)<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array with all members except the first from {{Code|$array}}. This function is equivalent to the expression {{Code|array:remove($array, 1)}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} The array is empty.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:insert-before(["a"], 1, "b")</code> returns the array {{Code|["b", "a"]}}.<br />
|}<br />
<br />
==array:reverse==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:reverse(<br />
$array as array(*)<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array with all members of {{Code|$array}} in reverse order.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:reverse(array { 1 to 3 })</code> returns the array {{Code|[3, 2, 1]}}.<br />
|}<br />
<br />
==array:join==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:join(<br />
$arrays as array(*)*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Concatenates the contents of several {{Code|$arrays}} into a single array.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:join(())</code> returns the array {{Code|[]}}.<br />
* <code>array:join((1 to 3) ! array { . })</code> returns the array {{Code|[1, 2, 3]}}.<br />
|}<br />
<br />
==array:flatten==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:flatten(<br />
$items as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Recursively flattens all arrays that occur in the supplied {{Code|$items}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:flatten(["a","b"])</code> returns the sequence {{Code|"a", "b"}}.<br />
* <code>array:flatten([1,[2,3],4]])</code> returns the sequence {{Code|1, 2, 3, 4}}.<br />
|}<br />
<br />
==array:for-each==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:for-each(<br />
$array as array(*),<br />
$action as function(item()*) as item()*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array, in which each member is computed by applying {{Code|$action}} to the corresponding member of {{Code|$array}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|The following query returns the array {{Code|[2, 3, 4, 5, 6]}}:<br />
<br />
<syntaxhighlight lang="xquery"><br />
array:for-each(<br />
array { 1 to 5 },<br />
function($i) { $i + 1}<br />
)<br />
</syntaxhighlight><br />
|}<br />
<br />
==array:filter==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:filter(<br />
$array as array(*),<br />
$predicate as function(item()*) as xs:boolean<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array with those members of {{Code|$array}} for which {{Code|$predicate}} returns {{Code|true}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|The following query returns the array {{Code|[0, 1, 3]}}:<br />
<syntaxhighlight lang="xquery"><br />
array:filter(<br />
array { 0, 1, -2, 3, -4 },<br />
function($i) { $i > 0 }<br />
)<br />
</syntaxhighlight><br />
|}<br />
<br />
==array:fold-left==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:fold-left(<br />
$array as array(*),<br />
$zero as item()*,<br />
$action as function(item()*, item()*) as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Evaluates the supplied {{Code|$action}} cumulatively on successive members of the supplied {{Code|$array}} from left to right, and uses {{Code|$zero}} as first argument.<br />
|- valign="top"<br />
| '''Examples'''<br />
|The following query returns {{Code|55}} (the sum of the integers 1 to 10):<br />
<syntaxhighlight lang="xquery"><br />
array:fold-left(<br />
array { 1 to 10 },<br />
0,<br />
function($a, $b) { $a + $b }<br />
)<br />
</syntaxhighlight><br />
|}<br />
<br />
==array:fold-right==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:fold-right(<br />
$array as array(*),<br />
$zero as item()*,<br />
$action as function(item()*, item()*) as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Evaluates the supplied {{Code|$action}} cumulatively on successive members of the supplied {{Code|$array}} from right to left, and uses {{Code|$zero}} as first argument.<br />
|- valign="top"<br />
| '''Examples'''<br />
|The following query is equivalent to the expression <code>array:reverse(array { 1 to 5 })</code>:<br />
<syntaxhighlight lang="xquery"><br />
array {<br />
array:fold-right(<br />
array { 1 to 5 },<br />
(),<br />
function($a, $b) { $b, $a }<br />
)<br />
}<br />
</syntaxhighlight><br />
|}<br />
<br />
==array:for-each-pair==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:for-each-pair(<br />
$array1 as array(*),<br />
$array2 as array(*),<br />
$action as function(item()*) as item()*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array obtained by evaluating the supplied {{Code|$action}} for each pair of members at the same position in {{Code|$array1}} and {{Code|$array2}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|The following query returns the array {{Code|[5, 7, 9]}}:<br />
<syntaxhighlight lang="xquery"><br />
array:for-each-pair(<br />
array { 1 to 3 },<br />
array { 4 to 6 },<br />
function($a + $b) { $a + $b }<br />
)<br />
</syntaxhighlight><br />
|}<br />
<br />
==array:sort==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:sort(<br />
$array as array(*),<br />
$collation as xs:string? := (),<br />
$key as function(item()*) as xs:anyAtomicType*) := ()<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array with sorted {{Code|$array}} members, using an optional {{Code|$collation}}. If a {{Code|$key}} function is supplied, it will be applied on all array members. The items of the resulting values will be sorted using the semantics of the {{Code|lt}} expression.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:sort(array { reverse(1 to 3) })</code> returns <code>[1, 2, 3]</code><br />
* <code>array:sort([3,-2,1], (), abs#1)</code> returns <code>[1, -2, 3]</code><br />
* <code>array:sort([1,2,3], (), function($x) { -$x })</code> returns <code>[3, 2, 1]</code><br />
* <code>array:sort((1,'a'))</code> returns an error (strings and integers cannot be compared)<br />
|}<br />
<br />
=Errors=<br />
<br />
{| class="wikitable" width="100%"<br />
! width="110"|Code<br />
|Description<br />
|- valign="top"<br />
|{{Code|FOAY0001}}<br />
|The specified index extends beyonds the bounds of an array.<br />
|- valign="top"<br />
|{{Code|FOAY0002}}<br />
|The specified length is less than zero.<br />
|}<br />
<br />
=Changelog=<br />
<br />
;Version 8.6<br />
* Updated: {{Function||array:put}} collation argument was inserted between first and second argument.<br />
<br />
;Version 8.5<br />
* Added: {{Function||array:put}}<br />
<br />
;Version 8.4<br />
* Removed: array:serialize (use fn:serialize instead)<br />
<br />
Introduced with Version 8.0.</div>Andy Buncehttps://docs.basex.org/index.php?title=String_Module&diff=16573String Module2023-07-03T13:16:22Z<p>Andy Bunce: comment variadic indicator</p>
<hr />
<div>{{Announce|Updated with Version 10:}} Renamed from ''Strings Module'' to ''String Module''. The namespace URI has been updated as well.<br />
<br />
This [[Module Library|XQuery Module]] contains functions for string operations and computations.<br />
<br />
=Conventions=<br />
<br />
All functions and errors in this module and errors are assigned to the <code><nowiki>http://basex.org/modules/string</nowiki></code> namespace, which is statically bound to the {{Code|string}} prefix.<br/><br />
<br />
=Computations=<br />
<br />
==string:levenshtein==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>string:levenshtein(<br />
$string1 as xs:string,<br />
$string2 as xs:string<br />
) as xs:double</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Computes the [https://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance Damerau-Levenshtein Distance] for two strings and returns a double value ({{Code|0.0}} - {{Code|1.0}}). The returned value is computed as follows:<br/><br />
* <code>1.0</code> – distance / max(length of strings)<br />
* <code>1.0</code> is returned if the strings are equal; <code>0.0</code> is returned if the strings are too different.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|string:levenshtein("flower", "flower")}} returns {{Code|1}}<br />
* {{Code|string:levenshtein("flower", "lewes")}} returns {{Code|0.5}}<br />
* In the following query, the input is first normalized (words are stemmed, converted to lower case, and diacritics are removed). It returns {{Code|1}}:<br />
<syntaxhighlight lang="xquery"><br />
let $norm := ft:normalize(?, map { 'stemming': true() })<br />
return string:levenshtein($norm("HOUSES"), $norm("house"))<br />
</syntaxhighlight><br />
|}<br />
<br />
==string:soundex==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>string:soundex(<br />
$string as xs:string<br />
) as xs:string</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Computes the [https://en.wikipedia.org/wiki/Soundex Soundex] value for the specified string. The algorithm can be used to find and index English words with similar pronouncation.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>string:soundex("Michael")</code> returns {{Code|M240}}<br />
* <code>string:soundex("OBrien") = string:soundex("O'Brien")</code> returns {{Code|true}}<br />
|}<br />
<br />
==string:cologne-phonetic==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>string:cologne-phonetic(<br />
$string as xs:string<br />
) as xs:string</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Computes the [https://de.wikipedia.org/wiki/K%C3%B6lner_Phonetik Kölner Phonetik] value for the specified string. Similar to Soundex, the algorithm is used to find similarly pronounced words, but for the German language. As the first returned digit can be {{Code|0}}, the value is returned as string.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>string:cologne-phonetic("Michael")</code> returns {{Code|645}}<br />
* <code>every $s in ("Mayr", "Maier", "Meier") satisfies string:cologne-phonetic($s) = "67"</code> returns {{Code|true}}<br />
|}<br />
<br />
=Formatting=<br />
<br />
{{Announce|The functions in this section have been adopted from the obsolete Output Module.}}<br />
<br />
==string:format==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>string:format(<br />
$format as xs:string,<br />
$inputs as item() (: ... :)<br />
) as xs:string</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns a formatted string. The remaining {{Code|$input}} are inserted to the {{Code|$format}} string, according to [https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html#syntax Java’s printf syntax].<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|format|#Errors}} The specified format is not valid.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|string:format("%b", true())}} returns {{Code|true}}.<br />
* {{Code|string:format("%06d", 256)}} returns {{Code|000256}}.<br />
* {{Code|string:format("%e", 1234.5678)}} returns {{Code|1.234568e+03}}.<br />
|}<br />
<br />
==string:cr==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|{{Code|'''string:cr()''' as xs:string}}<br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns a single carriage return character ({{Code|&amp;#13;}}).<br />
|}<br />
<br />
==string:nl==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|{{Code|'''string:nl()''' as xs:string}}<br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns a single newline character ({{Code|&amp;#10;}}).<br />
|}<br />
<br />
==string:tab==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|{{Code|'''string:tab()''' as xs:string}}<br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns a single tabulator character ({{Code|&amp;#9;}}).<br />
|}<br />
<br />
=Changelog=<br />
<br />
;Version 10.0<br />
* Updated: Renamed from ''Strings Module'' to ''String Module''. The namespace URI has been updated as well.<br />
* Updated: {{Function||string:format}}, {{Function||string:cr}}, {{Function||string:nl}} and {{Function||string:tab}} adopted from the obsolete Output Module.<br />
<br />
The Module was introduced with Version 8.3. Functions were adopted from the obsolete Utility and Output Modules.</div>Andy Buncehttps://docs.basex.org/index.php?title=Update_Module&diff=16572Update Module2023-07-03T13:13:22Z<p>Andy Bunce: add return types for function args in signatures</p>
<hr />
<div>This [[Module Library|XQuery Module]] provides additional functions for performing updates and returning results in [[XQuery Update|updating expressions]].<br />
<br />
=Conventions=<br />
<br />
All functions in this module are assigned to the <code><nowiki>http://basex.org/modules/update</nowiki></code> namespace, which is statically bound to the {{Code|update}} prefix.<br/><br />
<br />
Except for {{Function||update:output-cache}}, all functions are ''updating'' and thus comply to the XQuery Update constraints.<br />
<br />
=Updates=<br />
<br />
==update:apply==<br />
<br />
{|<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>update:apply(<br />
$function as function(*),<br />
$arguments as array(*)<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|The updating variant of [[XQuery 3.1#fn:apply|fn:apply]] applies the specified updating <code>$function</code> to the specified <code>$arguments</code>.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* Creates a new database with an initial document and adds a document to an existing database.<br />
<syntaxhighlight lang="xquery"><br />
declare %updating function local:update(<br />
$database as xs:string,<br />
$path as xs:string,<br />
$function as %updating function(item(), xs:string) as empty-sequence()<br />
) as empty-sequence() {<br />
update:apply($function, [ $database, $path ])<br />
};<br />
local:update('new-db', 'doc.xml', db:create#2),<br />
local:update('existing-db', 'doc.xml', db:add#2)<br />
</syntaxhighlight><br />
|}<br />
<br />
==update:for-each==<br />
<br />
{|<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>update:for-each(<br />
$input as item()*,<br />
$action as function(item()) as item()*<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|The updating variant of [[Higher-Order Functions#fn:for-each|fn:for-each]] applies the specified updating <code>$action</code> to every item of <code>$input</code>.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* Creates two databases:<br />
<syntaxhighlight lang="xquery"><br />
let $names := ('db1', 'db2')<br />
return update:for-each($names, db:create#1)<br />
</syntaxhighlight><br />
|}<br />
<br />
==update:for-each-pair==<br />
<br />
{|<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>update:for-each-pair(<br />
$input1 as item()*,<br />
$input2 as item()*,<br />
$action as function(item()) as item()*<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|The updating variant of [[Higher-Order Functions#fn:for-each-pair|fn:for-each-pair]] applies the specified updating <code>$action</code> to the successive pairs of items of <code>$input1</code> and <code>$input2</code>. Evaluation is stopped if one sequence yields no more items.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* Renames nodes in an XML snippets:<br />
<syntaxhighlight lang="xquery"><br />
copy $xml := <xml><a/><b/></xml><br />
modify update:for-each-pair(<br />
('a', 'b'),<br />
('d', 'e'),<br />
function($source, $target) {<br />
for $e in $xml/*[name() = $source]<br />
return rename node $e as $target<br />
}<br />
)<br />
return $xml<br />
</syntaxhighlight><br />
|}<br />
<br />
==update:map-for-each==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>update:map-for-each(<br />
$map as map(*),<br />
$action as function(xs:anyAtomicType, item()*) as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|The updating variant of {{Function|Map|map:for-each}} applies the specified {{Code|$action}} to every key/value pair of the supplied {{Code|$map}} and returns the results as a sequence.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* Inserts attributes into a document:<br />
<syntaxhighlight lang="xquery"><br />
copy $doc := <xml/><br />
modify update:map-for-each(<br />
map {<br />
'id': 'id0',<br />
'value': 456<br />
},<br />
function($key, $value) {<br />
insert node attribute { $key } { $value } into $doc<br />
}<br />
)<br />
return $doc</syntaxhighlight><br />
|}<br />
<br />
=Output=<br />
<br />
==update:output==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>update:output(<br />
$input as item()*<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|This function can be used if {{Option|MIXUPDATES}} is not enabled, and if values need to be returned within an updating expression: The supplied {{Code|$input}} will be cached and returned at the very end, i.e., after all updates on the ''pending update list'' have been processed. If one of the supplied items is affected by an update, a copy will be created and cached instead.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|update:output("Prices have been deleted."), delete node //price}} deletes all {{Code|price}} elements in a database and returns an info message.<br />
|}<br />
<br />
==update:cache==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>update:cache(<br />
$reset as xs:boolean? := false()<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the items that have been cached by {{Function||update:output}}. The output cache can optionally be {{Code|$reset}}. The function can be used to check which items will eventually be returned as the result of an updating function.<br/>This function is ''non-deterministic'': It will return different results before and after items have been cached. The function can be useful for writing [[Unit Module|unit tests]].<br />
|}<br />
<br />
=Changelog=<br />
<br />
;Version 9.3<br />
* {{Function||update:cache}}: {{code|$reset}} parameter added.<br />
<br />
;Version 9.1<br />
* {{Function||update:output}}: Maps and arrays can be cached if they contain no persistent database nodes or function items.<br />
<br />
;Version 9.0<br />
* Updated: db:output renamed to {{Function||update:output}}, db:output-cache renamed to {{Function||update:cache}}<br />
<br />
This module was introduced with Version 9.0.</div>Andy Buncehttps://docs.basex.org/index.php?title=Higher-Order_Functions_Module&diff=16571Higher-Order Functions Module2023-07-03T13:06:25Z<p>Andy Bunce: signatures</p>
<hr />
<div>This [[Module Library|XQuery Module]] adds some useful higher-order functions, additional to the [[Higher-Order Functions]] provided by the official specification.<br />
<br />
=Conventions=<br />
<br />
All functions in this module are assigned to the <code><nowiki>http://basex.org/modules/hof</nowiki></code> namespace, which is statically bound to the {{Code|hof}} prefix.<br/><br />
<br />
=Loops=<br />
<br />
==hof:fold-left1==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>hof:fold-left1(<br />
$input as item()+,<br />
$action as function(item()*, item()) as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Works the same as [[Higher-Order Functions#fn:fold-left|fn:fold-left]], but does not need a seed, because the sequence must be non-empty.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|hof:fold-left1(1 to 10, function($a, $b) { $a + $b })}} returns {{Code|55}}.<br />
* {{Code|hof:fold-left1((), function($a, $b) { $a + $b })}} throws {{Code|XPTY0004}}, because {{Code|$seq}} has to be non-empty.<br />
|}<br />
<br />
==hof:until==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>hof:until(<br />
$predicate as function(item()*) as xs:boolean,<br />
$action as function(item()*) as item()*,<br />
$zero as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Applies the predicate function {{Code|$predicate}} to {{Code|$zero}}. If the result is {{Code|false}}, {{Code|$action}} is invoked with the start value – or, subsequently, with the result of this function – until the predicate function returns {{Code|true()}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* Doubles a numeric value until a maximum is reached:<br />
<syntaxhighlight lang="xquery"><br />
hof:until(<br />
function($output) { $output ge 1000 },<br />
function($input ) { 2 * $input },<br />
1<br />
)<br />
</syntaxhighlight><br />
* Calculates the square root of a number by iteratively improving an initial guess:<br />
<syntaxhighlight lang="xquery"><br />
let $sqrt := function($input as xs:double) as xs:double {<br />
hof:until(<br />
function($result) { abs($result * $result - $input) < 0.00001 },<br />
function($guess) { ($guess + $input div $guess) div 2 },<br />
$input<br />
)<br />
}<br />
return $sqrt(25)<br />
</syntaxhighlight><br />
* Returns {{Code|OK}}, as the predicate is evaluated first:<br />
<syntaxhighlight lang="xquery"><br />
hof:until(<br />
function($_) { true() },<br />
function($_) { error() },<br />
'OK'<br />
)<br />
</syntaxhighlight><br />
|}<br />
<br />
==hof:scan-left==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>hof:scan-left(<br />
$input as item()*,<br />
$zero as item()*,<br />
$action as function(item()*, item()) as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|This function is similar to [[Higher-Order Functions#fn:fold-left|fn:fold-left]], but it returns a list of successive reduced values from the left. It is equivalent to:<br />
<syntaxhighlight lang="xquery"><br />
declare function hof:scan-left($input, $acc, $action) {<br />
if(empty($input)) then $acc else (<br />
$acc,<br />
hof:scan-left(tail($input), $action($acc, head($input)), $action)<br />
)<br />
};<br />
</syntaxhighlight><br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* Returns triangular numbers:<br />
<syntaxhighlight lang="xquery"><br />
hof:scan-left(1 to 10, 0, function($a, $b) { $a + $b })<br />
</syntaxhighlight><br />
|}<br />
<br />
==hof:take-while==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>hof:take-while(<br />
$input as item()*,<br />
$predicate as function(item()) as xs:boolean<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|The function returns items of <code>$input</code> as long as the <code>$predicate</code> is satisfied. It is equivalent to:<br />
<syntaxhighlight lang="xquery"><br />
declare function hof:take-while($input, $predicate) {<br />
if(empty($input) or not($predicate(head($input)))) then () else (<br />
head($input),<br />
hof:take-while(tail($input), $predicate)<br />
)<br />
};<br />
</syntaxhighlight><br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* Computes at most 100 random integers, but stops if an integer is smaller than 10:<br />
<syntaxhighlight lang="xquery"><br />
hof:take-while(<br />
(1 to 100) ! random:integer(50),<br />
function($x) { $x >= 10 }<br />
)<br />
</syntaxhighlight><br />
|}<br />
<br />
==hof:drop-while==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>hof:drop-while(<br />
$input as item()*,<br />
$predicate as function(item()*) as xs:boolean<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|The function skips all items of <code>$input</code> until the <code>$predicate</code> is not satisfied anymore. It is equivalent to:<br />
<syntaxhighlight lang="xquery"><br />
declare function hof:drop-while($input, $predicate) {<br />
if($predicate(head($input))) then (<br />
hof:drop-while(tail($input), $predicate)<br />
) else (<br />
$input<br />
)<br />
};<br />
</syntaxhighlight><br />
|- valign="top"<br />
| '''Examples'''<br />
|Returns the name of the first file that does not exist on disk:<br />
<syntaxhighlight lang="xquery"><br />
hof:drop-while(<br />
(1 to 1000) ! (. || '.log'),<br />
file:exists#1<br />
)[1]<br />
</syntaxhighlight><br />
|}<br />
<br />
=Sorting=<br />
<br />
==hof:top-k-by==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>hof:top-k-by(<br />
$input as item()*<br />
$key as function(item()) as item()<br />
$k as xs:integer<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the {{Code|$k}} items in {{Code|$input}} that are greatest when sorted by the result of {{Code|$key}} applied to the item. The function is a much more efficient implementation of the following scheme:<br />
<syntaxhighlight lang="xquery"><br />
(for $item in $input<br />
order by $key($item) descending<br />
return $item<br />
)[position() <= $k]<br />
</syntaxhighlight><br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|hof:top-k-by(1 to 1000, hof:id#1, 5)}} returns {{Code|1000 999 998 997 996}}<br />
* {{Code|hof:top-k-by(1 to 1000, function($x) { -$x }, 3)}} returns {{Code|1 2 3}}<br />
* <code>hof:top-k-by(<x a='1' b='2' c='3'/>/@*, xs:integer#1, 2)/node-name()</code> returns {{Code|c b}}<br />
|}<br />
<br />
==hof:top-k-with==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>hof:top-k-with(<br />
$input as item()*<br />
$comparator as function(item(), item()) as xs:boolean<br />
$k as xs:integer<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the {{Code|$k}} items in {{Code|$input}} that are greatest when sorted in the order of the ''less-than'' predicate {{Code|$comparator}}. The function is a general version of {{Function||hof:top-k-by}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|hof:top-k-with(1 to 1000, function($a, $b) { $a lt $b }, 5)}} returns {{Code|1000 999 998 997 996}}<br />
* {{Code|hof:top-k-with(-5 to 5, function($a, $b) { abs($a) gt abs($b) }, 5)}} returns {{Code|0 1 -1 2 -2}}<br />
|}<br />
<br />
=IDs=<br />
<br />
==hof:id==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>hof:id(<br />
$input as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns its argument unchanged. This function isn’t useful on its own, but can be used as an argument to other higher-order functions.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|hof:id(1 to 5)}} returns {{Code|1 2 3 4 5}}<br />
* With higher-order functions:<br />
<syntaxhighlight lang="xquery"><br />
let $sort := sort(?, (), hof:id#1)<br />
let $reverse-sort := sort(?, (), function($x) { -$x })<br />
return (<br />
$sort((1, 5, 3, 2, 4)),<br />
'|',<br />
$reverse-sort((1, 5, 3, 2, 4))<br />
)<br />
</syntaxhighlight><br />
returns: <code>1 2 3 4 5 | 5 4 3 2 1</code><br />
|}<br />
<br />
==hof:const==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>hof:const(<br />
$input as item()*,<br />
$ignore as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns its first argument unchanged and ignores the second. This function isn’t useful on its own, but can be used as argument to other higher-order functions, e.g., when a function combining two values is expected and one only wants to retain the left one.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|hof:const(42, 1337)}} returns {{Code|42}}.<br />
* With higher-order functions:<br />
<syntaxhighlight lang="xquery"><br />
let $zip-sum := function($f, $seq1, $seq2) {<br />
sum(for-each-pair($seq1, $seq2, $f))<br />
}<br />
let $sum-all := $zip-sum(function($a, $b) { $a + $b }, ?, ?)<br />
let $sum-left := $zip-sum(hof:const#2, ?, ?)<br />
return (<br />
$sum-all((1, 1, 1, 1, 1), 1 to 5),<br />
$sum-left((1, 1, 1, 1, 1), 1 to 5)<br />
)<br />
</syntaxhighlight><br />
* Another use-case: When inserting a key into a map, {{Code|$f}} decides how to combine the new value with a possibly existing old one. {{Code|hof:const}} here means ignoring the old value, so that's normal insertion.<br />
<syntaxhighlight lang="xquery"><br />
let $insert-with := function($f, $map, $k, $v) {<br />
let $old := $map($k)<br />
let $new := if($old) then $f($v, $old) else $v<br />
return map:merge(($map, map:entry($k, $new)))<br />
}<br />
let $map := map { 'foo': 1 }<br />
let $add := $insert-with(function($a, $b) { $a + $b }, ?, ?, ?)<br />
let $ins := $insert-with(hof:const#2, ?, ?, ?)<br />
return (<br />
$add($map, 'foo', 2)('foo'),<br />
$ins($map, 'foo', 42)('foo')<br />
)<br />
</syntaxhighlight><br />
returns {{Code|3 42}}<br />
|}<br />
<br />
=Changelog=<br />
<br />
;Version 9.5<br />
* Added: {{Function||hof:drop-while}}<br />
<br />
;Version 8.1<br />
* Added: {{Function||hof:scan-left}}, {{Function||hof:take-while}}<br />
<br />
;Version 7.2<br />
* Added: {{Function||hof:top-k-by}}, {{Function||hof:top-k-with}}<br />
* Removed: hof:iterate<br />
<br />
;Version 7.0<br />
* module added</div>Andy Buncehttps://docs.basex.org/index.php?title=Array_Module&diff=16570Array Module2023-07-03T13:02:49Z<p>Andy Bunce: add return types for function args in signatures</p>
<hr />
<div>This [[Module Library|XQuery Module]] contains functions for manipulating arrays, which has been introduced with [[XQuery 3.1#Arrays|XQuery 3.1]].<br />
<br />
=Conventions=<br />
<br />
All functions and errors in this module are assigned to the <code><nowiki>http://www.w3.org/2005/xpath-functions/array</nowiki></code> namespace, which is statically bound to the {{Code|array}} prefix.<br/><br />
<br />
=Functions=<br />
<br />
==array:size==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:size(<br />
$array as array(*)<br />
) as xs:integer</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns the number of members in {{Code|$array}}. Note that because an array is an item, the {{Code|fn:count}} function when applied to an array always returns {{Code|1}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:size(array { 1 to 10 })</code> returns {{Code|10}}.<br />
* <code>array:size([1 to 10])</code> returns {{Code|1}}, because the array contains a single sequence with 10 integers.<br />
|}<br />
<br />
==array:get==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:get(<br />
$array as array(*),<br />
$position as xs:integer<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns the {{Code|$array}} member at the specified {{Code|$position}}. <br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} {{Code|$position}} is not in the range {{Code|1}} to {{Code|array:size($array)}} inclusive.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:get(array { reverse(1 to 5) }, 5)</code> returns the value {{Code|1}}.<br />
|}<br />
<br />
==array:append==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:append(<br />
$array as array(*),<br />
$member as item()*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a copy of {{Code|$array}} with {{Code|$member}} attached.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:append([], 'member1')</code> returns the array {{Code|["member1"]}}.<br />
|}<br />
<br />
==array:subarray==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:subarray(<br />
$array as array(*),<br />
$position as xs:integer,<br />
$length as xs:integer := ()<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Constructs a new array with with {{Code|$length}} members of {{Code|$array}} beginning from the specified {{Code|$position}}.<br/>The two-argument version of the function returns the same result as the three-argument version when called with {{Code|$length}} equal to the value of {{Code|array:size($array) - $position + 1}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} {{Code|$position}} is less than one, or if {{Code|$position + $length}} is greater than {{Code|array:size($array) + 1}}.<br/>{{Error|FOAY0002|#Errors}} {{Code|$length}} is less than zero.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:subarray(["a", "b", "c"], 2)</code> returns the array {{Code|["b", "c"]}}.<br />
|}<br />
<br />
==array:put==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:put(<br />
$array as array(*),<br />
$position as xs:integer,<br />
$member as item()*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a copy of {{Code|$array}} with {{Code|$member}} replaced at the specified {{Code|$position}}. Equivalent to <code>$array => array:remove($position) => array:insert-before($position, $member)</code>.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} {{Code|$position}} is not in the range {{Code|1}} to {{Code|array:size($array)}} inclusive.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:put(["a", "b", "c"], 2, "d")</code> returns the array {{Code|["a", "d", "c"]}}.<br />
|}<br />
<br />
==array:remove==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:remove(<br />
$array as array(*),<br />
$positions as xs:integer*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a copy of {{Code|$array}} without the member at the specified {{Code|$positions}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} A position is not in the range {{Code|1}} to {{Code|array:size($array)}} inclusive.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:append(["a"], 1)</code> returns the array {{Code|[]}}.<br />
|}<br />
<br />
==array:insert-before==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:insert-before(<br />
$array as array(*),<br />
$position as xs:integer,<br />
$member as item()*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a copy of {{Code|$array}} with one new {{Code|$member}} at the specified {{Code|$position}}. Setting {{Code|$position}} to the value {{Code|array:size($array) + 1}} yields the same result as {{Code|array:append($array, $insert)}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} {{Code|$position}} is not in the range {{Code|1}} to {{Code|array:size($array) + 1}} inclusive.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:insert-before(["a"], 1, "b")</code> returns the array {{Code|["b", "a"]}}.<br />
|}<br />
<br />
==array:head==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:head(<br />
$array as array(*)<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns the first member of {{Code|$array}}. This function is equivalent to the expression {{Code|$array(1)}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} The array is empty.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:head(["a", "b"])</code> returns {{Code|"a"}}.<br />
* <code>array:head([["a", "b"], ["c", "d"]])</code> returns the array {{Code|["a", "b"]}}.<br />
|}<br />
<br />
==array:tail==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:tail(<br />
$array as array(*)<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array with all members except the first from {{Code|$array}}. This function is equivalent to the expression {{Code|array:remove($array, 1)}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|FOAY0001|#Errors}} The array is empty.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:insert-before(["a"], 1, "b")</code> returns the array {{Code|["b", "a"]}}.<br />
|}<br />
<br />
==array:reverse==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:reverse(<br />
$array as array(*)<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array with all members of {{Code|$array}} in reverse order.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:reverse(array { 1 to 3 })</code> returns the array {{Code|[3, 2, 1]}}.<br />
|}<br />
<br />
==array:join==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:join(<br />
$arrays as array(*)*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Concatenates the contents of several {{Code|$arrays}} into a single array.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:join(())</code> returns the array {{Code|[]}}.<br />
* <code>array:join((1 to 3) ! array { . })</code> returns the array {{Code|[1, 2, 3]}}.<br />
|}<br />
<br />
==array:flatten==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:flatten(<br />
$items as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Recursively flattens all arrays that occur in the supplied {{Code|$items}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:flatten(["a","b"])</code> returns the sequence {{Code|"a", "b"}}.<br />
* <code>array:flatten([1,[2,3],4]])</code> returns the sequence {{Code|1, 2, 3, 4}}.<br />
|}<br />
<br />
==array:for-each==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:for-each(<br />
$array as array(*),<br />
$action as function(item()*) as item()*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array, in which each member is computed by applying {{Code|$action}} to the corresponding member of {{Code|$array}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|The following query returns the array {{Code|[2, 3, 4, 5, 6]}}:<br />
<br />
<syntaxhighlight lang="xquery"><br />
array:for-each(<br />
array { 1 to 5 },<br />
function($i) { $i + 1}<br />
)<br />
</syntaxhighlight><br />
|}<br />
<br />
==array:filter==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:filter(<br />
$array as array(*),<br />
$predicate as function(item()*) as xs:boolean<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array with those members of {{Code|$array}} for which {{Code|$predicate}} returns {{Code|true}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|The following query returns the array {{Code|[0, 1, 3]}}:<br />
<syntaxhighlight lang="xquery"><br />
array:filter(<br />
array { 0, 1, -2, 3, -4 },<br />
function($i) { $i > 0 }<br />
)<br />
</syntaxhighlight><br />
|}<br />
<br />
==array:fold-left==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:fold-left(<br />
$array as array(*),<br />
$zero as item()*,<br />
$action as function(item()*, item()*) as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Evaluates the supplied {{Code|$action}} cumulatively on successive members of the supplied {{Code|$array}} from left to right, and uses {{Code|$zero}} as first argument.<br />
|- valign="top"<br />
| '''Examples'''<br />
|The following query returns {{Code|55}} (the sum of the integers 1 to 10):<br />
<syntaxhighlight lang="xquery"><br />
array:fold-left(<br />
array { 1 to 10 },<br />
0,<br />
function($a, $b) { $a + $b }<br />
)<br />
</syntaxhighlight><br />
|}<br />
<br />
==array:fold-right==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:fold-right(<br />
$array as array(*),<br />
$zero as item()*,<br />
$action as function(item()*, item()*) as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Evaluates the supplied {{Code|$action}} cumulatively on successive members of the supplied {{Code|$array}} from right to left, and uses {{Code|$zero}} as first argument.<br />
|- valign="top"<br />
| '''Examples'''<br />
|The following query is equivalent to the expression <code>array:reverse(array { 1 to 5 })</code>:<br />
<syntaxhighlight lang="xquery"><br />
array {<br />
array:fold-right(<br />
array { 1 to 5 },<br />
(),<br />
function($a, $b) { $b, $a }<br />
)<br />
}<br />
</syntaxhighlight><br />
|}<br />
<br />
==array:for-each-pair==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:for-each-pair(<br />
$array1 as array(*),<br />
$array2 as array(*),<br />
$action as function(item()*) as item()*<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array obtained by evaluating the supplied {{Code|$action}} for each pair of members at the same position in {{Code|$array1}} and {{Code|$array2}}.<br />
|- valign="top"<br />
| '''Examples'''<br />
|The following query returns the array {{Code|[5, 7, 9]}}:<br />
<syntaxhighlight lang="xquery"><br />
array:for-each-pair(<br />
array { 1 to 3 },<br />
array { 4 to 6 },<br />
function($a + $b) { $a + $b }<br />
)<br />
</syntaxhighlight><br />
|}<br />
<br />
==array:sort==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>array:sort(<br />
$array as array(*),<br />
$collation as xs:string? := (),<br />
$key as function(item()*) := ()<br />
) as array(*)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| Returns a new array with sorted {{Code|$array}} members, using an optional {{Code|$collation}}. If a {{Code|$key}} function is supplied, it will be applied on all array members. The items of the resulting values will be sorted using the semantics of the {{Code|lt}} expression.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>array:sort(array { reverse(1 to 3) })</code> returns <code>[1, 2, 3]</code><br />
* <code>array:sort([3,-2,1], (), abs#1)</code> returns <code>[1, -2, 3]</code><br />
* <code>array:sort([1,2,3], (), function($x) { -$x })</code> returns <code>[3, 2, 1]</code><br />
* <code>array:sort((1,'a'))</code> returns an error (strings and integers cannot be compared)<br />
|}<br />
<br />
=Errors=<br />
<br />
{| class="wikitable" width="100%"<br />
! width="110"|Code<br />
|Description<br />
|- valign="top"<br />
|{{Code|FOAY0001}}<br />
|The specified index extends beyonds the bounds of an array.<br />
|- valign="top"<br />
|{{Code|FOAY0002}}<br />
|The specified length is less than zero.<br />
|}<br />
<br />
=Changelog=<br />
<br />
;Version 8.6<br />
* Updated: {{Function||array:put}} collation argument was inserted between first and second argument.<br />
<br />
;Version 8.5<br />
* Added: {{Function||array:put}}<br />
<br />
;Version 8.4<br />
* Removed: array:serialize (use fn:serialize instead)<br />
<br />
Introduced with Version 8.0.</div>Andy Buncehttps://docs.basex.org/index.php?title=Store_Module&diff=16569Store Module2023-07-03T11:58:56Z<p>Andy Bunce: signature formating</p>
<hr />
<div>This [[Module Library|XQuery Module]] provides functions to organize values in a persistent main-memory key-value store.<br />
<br />
The store is useful if data (a system configuration, maps serving as indexes) needs to be repeatedly accessed. The store is persistent: Contents will be written to disk at shutdown time, and the serialized store will be retrieved from disk as soon as the store is used for the first time. The store will be stored in a binary {{Code|store.basex}} file in the database directory.<br />
<br />
In addition, custom stores can be read and written. Custom stores have filenames with the pattern {{Code|store-NAME.basex}}. The implicit write of the standard store at shutdown time will be disabled if a custom store is used.<br />
<br />
Functions of this module are non-deterministic and side-effecting: Updates will immediately be visible, and a repeated call of the same function may yield different results if the contents of the store have changed.<br />
<br />
=Conventions=<br />
<br />
All functions and errors in this module are assigned to the <code><nowiki>http://basex.org/modules/store</nowiki></code> namespace, which is statically bound to the {{Code|store}} prefix.<br/><br />
<br />
=Key-value operations=<br />
<br />
==store:get==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:get(<br />
$key as xs:string<br />
) as item()*</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Retrieves an entry from the store with the given {{Code|$key}}. If the addressed entry does not exist, an empty sequence is returned.<br />
|}<br />
<br />
==store:put==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:put(<br />
$key as xs:string,<br />
$value as item()*<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Stores an entry with the given {{Code|$key}} and {{Code|$value}} in the store:<br />
* If the value is an empty sequence, the entry is removed.<br />
* If a value refers to an opened database or is [[Lazy Module|a lazy item]], its contents are materialized in main memory.<br />
* Values with function items are rejected.<br />
|}<br />
<br />
==store:get-or-put==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:get-or-put(<br />
$key as xs:string,<br />
$put as function(*)<br />
) as item()*</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Retrieves an entry from the store with the given {{Code|$key}}. The {{Code|$put}} function will only be invoked if the entry does not exist, and its result will be stored and returned instead.<br />
|}<br />
<br />
==store:remove==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:remove(<br />
$key as xs:string<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Removes an entry with the given {{Code|$key}} from the store. No error will be raised if an addressed entry does not exist.<br />
|}<br />
<br />
==store:keys==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:keys() as xs:string*</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Lists the names of all keys.<br />
|}<br />
<br />
==store:clear==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:clear() as empty-sequence()</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Resets the store by removing all its entries.<br />
|}<br />
<br />
=Store Operations=<br />
<br />
==store:read==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:read(<br />
$name as xs:string? := ()<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Retrieves the standard store from disk, or a custom store if a {{Code|$name}} is supplied.<br />
|- valign="top"<br />
|'''Errors'''<br />
|{{Error|io|#Errors}} The store could not be read.<br/>{{Error|name|#Errors}} The specified name is invalid.<br/>{{Error|not-found|#Errors}} A store with the specified name does not exist.<br />
|}<br />
<br />
==store:write==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:write(<br />
$name as xs:string? := ()<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Writes the standard store to disk, or to a custom store file if a {{Code|$name}} is supplied. If the standard store is empty, the store file will be deleted.<br />
|- valign="top"<br />
|'''Errors'''<br />
|{{Error|io|#Errors}} The store could not be written.<br/>{{Error|name|#Errors}} The specified name is invalid.<br />
|}<br />
<br />
==store:list==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:list() as xs:string*</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Lists the names of all custom stores.<br />
|}<br />
<br />
==store:delete==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:delete(<br />
$name as xs:string<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Deletes a custom store from disk.<br />
|- valign="top"<br />
|'''Errors'''<br />
|{{Error|name|#Errors}} The specified name is invalid.<br/>{{Error|not-found|#Errors}} A store with the specified name does not exist.<br />
|}<br />
<br />
=Examples=<br />
<br />
'''Use Case 1: Create/update a system configuration in a running BaseX server instance:<br />
<br />
<syntaxhighlight lang="xquery"><br />
(: store an integer :)<br />
store:put('version', 1),<br />
(: retrieve existing or new value, store an element :)<br />
let $license := store:get-or-put('license', function() { 'free' })<br />
return store:put('info', <info>{ $license = 'free' ?? 'Free' !! 'Professional' } License</info>),<br />
(: store a map :)<br />
store:put('data', map { 'year': 2022 }),<br />
(: serialize configuration to disk :)<br />
store:write()<br />
</syntaxhighlight><br />
<br />
The configuration can be requested by further operations, e.g. a client request:<br />
<br />
<syntaxhighlight lang="xquery"><br />
store:get('version')<br />
</syntaxhighlight><br />
<br />
The store will still be available if BaseX is restarted until it is cleared.<br />
<br />
'''Use Case 2: Create index for fast lookup operations in the GUI:<br />
<br />
<syntaxhighlight lang="xquery"><br />
let $map := map:merge(<br />
for $country in db:get('factbook')//country<br />
for $religion in $country//religions<br />
group by $religion<br />
return map:entry($religion, data($country/@name))<br />
)<br />
return store:put('religions', $map)<br />
</syntaxhighlight><br />
<br />
A subsequent query can be used to access its contents:<br />
<br />
<syntaxhighlight lang="xquery"><br />
store:get('religions')?Buddhism<br />
</syntaxhighlight><br />
<br />
Note that the store will eventually be written to disk unless it is invalidated before closing the GUI.<br />
<br />
=Errors=<br />
<br />
{| class="wikitable" width="100%"<br />
! width="110"|Code<br />
|Description<br />
|- valign="top"<br />
|{{Code|io}}<br />
| The store could not be read or written.<br />
|- valign="top"<br />
|{{Code|name}}<br />
| The specified name is invalid.<br />
|- valign="top"<br />
|{{Code|not-found}}<br />
| A store with the specified name does not exist.<br />
|}<br />
<br />
=Changelog=<br />
<br />
The module was introduced with Version 10.</div>Andy Buncehttps://docs.basex.org/index.php?title=Store_Module&diff=16568Store Module2023-07-03T11:54:06Z<p>Andy Bunce: store:get-or-put signature</p>
<hr />
<div>This [[Module Library|XQuery Module]] provides functions to organize values in a persistent main-memory key-value store.<br />
<br />
The store is useful if data (a system configuration, maps serving as indexes) needs to be repeatedly accessed. The store is persistent: Contents will be written to disk at shutdown time, and the serialized store will be retrieved from disk as soon as the store is used for the first time. The store will be stored in a binary {{Code|store.basex}} file in the database directory.<br />
<br />
In addition, custom stores can be read and written. Custom stores have filenames with the pattern {{Code|store-NAME.basex}}. The implicit write of the standard store at shutdown time will be disabled if a custom store is used.<br />
<br />
Functions of this module are non-deterministic and side-effecting: Updates will immediately be visible, and a repeated call of the same function may yield different results if the contents of the store have changed.<br />
<br />
=Conventions=<br />
<br />
All functions and errors in this module are assigned to the <code><nowiki>http://basex.org/modules/store</nowiki></code> namespace, which is statically bound to the {{Code|store}} prefix.<br/><br />
<br />
=Key-value operations=<br />
<br />
==store:get==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:get(<br />
$key as xs:string<br />
) as item()*</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Retrieves an entry from the store with the given {{Code|$key}}. If the addressed entry does not exist, an empty sequence is returned.<br />
|}<br />
<br />
==store:put==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:put(<br />
$key as xs:string,<br />
$value as item()*<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Stores an entry with the given {{Code|$key}} and {{Code|$value}} in the store:<br />
* If the value is an empty sequence, the entry is removed.<br />
* If a value refers to an opened database or is [[Lazy Module|a lazy item]], its contents are materialized in main memory.<br />
* Values with function items are rejected.<br />
|}<br />
<br />
==store:get-or-put==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:get-or-put(<br />
$key as xs:string,<br />
$put as function(*)<br />
) as item()*</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Retrieves an entry from the store with the given {{Code|$key}}. The {{Code|$put}} function will only be invoked if the entry does not exist, and its result will be stored and returned instead.<br />
|}<br />
<br />
==store:remove==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:remove(<br />
$key as xs:string<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Removes an entry with the given {{Code|$key}} from the store. No error will be raised if an addressed entry does not exist.<br />
|}<br />
<br />
==store:keys==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:keys() as xs:string*</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Lists the names of all keys.<br />
|}<br />
<br />
==store:clear==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:clear() as empty-sequence()</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Resets the store by removing all its entries.<br />
|}<br />
<br />
=Store Operations=<br />
<br />
==store:read==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:read(<br />
$name as xs:string? :=()<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Retrieves the standard store from disk, or a custom store if a {{Code|$name}} is supplied.<br />
|- valign="top"<br />
|'''Errors'''<br />
|{{Error|io|#Errors}} The store could not be read.<br/>{{Error|name|#Errors}} The specified name is invalid.<br/>{{Error|not-found|#Errors}} A store with the specified name does not exist.<br />
|}<br />
<br />
==store:write==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:write(<br />
$name as xs:string? :=()<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Writes the standard store to disk, or to a custom store file if a {{Code|$name}} is supplied. If the standard store is empty, the store file will be deleted.<br />
|- valign="top"<br />
|'''Errors'''<br />
|{{Error|io|#Errors}} The store could not be written.<br/>{{Error|name|#Errors}} The specified name is invalid.<br />
|}<br />
<br />
==store:list==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:list() as xs:string*</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Lists the names of all custom stores.<br />
|}<br />
<br />
==store:delete==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:delete(<br />
$name as xs:string<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Deletes a custom store from disk.<br />
|- valign="top"<br />
|'''Errors'''<br />
|{{Error|name|#Errors}} The specified name is invalid.<br/>{{Error|not-found|#Errors}} A store with the specified name does not exist.<br />
|}<br />
<br />
=Examples=<br />
<br />
'''Use Case 1: Create/update a system configuration in a running BaseX server instance:<br />
<br />
<syntaxhighlight lang="xquery"><br />
(: store an integer :)<br />
store:put('version', 1),<br />
(: retrieve existing or new value, store an element :)<br />
let $license := store:get-or-put('license', function() { 'free' })<br />
return store:put('info', <info>{ $license = 'free' ?? 'Free' !! 'Professional' } License</info>),<br />
(: store a map :)<br />
store:put('data', map { 'year': 2022 }),<br />
(: serialize configuration to disk :)<br />
store:write()<br />
</syntaxhighlight><br />
<br />
The configuration can be requested by further operations, e.g. a client request:<br />
<br />
<syntaxhighlight lang="xquery"><br />
store:get('version')<br />
</syntaxhighlight><br />
<br />
The store will still be available if BaseX is restarted until it is cleared.<br />
<br />
'''Use Case 2: Create index for fast lookup operations in the GUI:<br />
<br />
<syntaxhighlight lang="xquery"><br />
let $map := map:merge(<br />
for $country in db:get('factbook')//country<br />
for $religion in $country//religions<br />
group by $religion<br />
return map:entry($religion, data($country/@name))<br />
)<br />
return store:put('religions', $map)<br />
</syntaxhighlight><br />
<br />
A subsequent query can be used to access its contents:<br />
<br />
<syntaxhighlight lang="xquery"><br />
store:get('religions')?Buddhism<br />
</syntaxhighlight><br />
<br />
Note that the store will eventually be written to disk unless it is invalidated before closing the GUI.<br />
<br />
=Errors=<br />
<br />
{| class="wikitable" width="100%"<br />
! width="110"|Code<br />
|Description<br />
|- valign="top"<br />
|{{Code|io}}<br />
| The store could not be read or written.<br />
|- valign="top"<br />
|{{Code|name}}<br />
| The specified name is invalid.<br />
|- valign="top"<br />
|{{Code|not-found}}<br />
| A store with the specified name does not exist.<br />
|}<br />
<br />
=Changelog=<br />
<br />
The module was introduced with Version 10.</div>Andy Buncehttps://docs.basex.org/index.php?title=Store_Module&diff=16567Store Module2023-07-03T11:47:21Z<p>Andy Bunce: sigs remove <br/> add missing optionals</p>
<hr />
<div>This [[Module Library|XQuery Module]] provides functions to organize values in a persistent main-memory key-value store.<br />
<br />
The store is useful if data (a system configuration, maps serving as indexes) needs to be repeatedly accessed. The store is persistent: Contents will be written to disk at shutdown time, and the serialized store will be retrieved from disk as soon as the store is used for the first time. The store will be stored in a binary {{Code|store.basex}} file in the database directory.<br />
<br />
In addition, custom stores can be read and written. Custom stores have filenames with the pattern {{Code|store-NAME.basex}}. The implicit write of the standard store at shutdown time will be disabled if a custom store is used.<br />
<br />
Functions of this module are non-deterministic and side-effecting: Updates will immediately be visible, and a repeated call of the same function may yield different results if the contents of the store have changed.<br />
<br />
=Conventions=<br />
<br />
All functions and errors in this module are assigned to the <code><nowiki>http://basex.org/modules/store</nowiki></code> namespace, which is statically bound to the {{Code|store}} prefix.<br/><br />
<br />
=Key-value operations=<br />
<br />
==store:get==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:get(<br />
$key as xs:string<br />
) as item()*</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Retrieves an entry from the store with the given {{Code|$key}}. If the addressed entry does not exist, an empty sequence is returned.<br />
|}<br />
<br />
==store:put==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:put(<br />
$key as xs:string,<br />
$value as item()*<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Stores an entry with the given {{Code|$key}} and {{Code|$value}} in the store:<br />
* If the value is an empty sequence, the entry is removed.<br />
* If a value refers to an opened database or is [[Lazy Module|a lazy item]], its contents are materialized in main memory.<br />
* Values with function items are rejected.<br />
|}<br />
<br />
==store:get-or-put==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:get-or-put(<br />
$key as xs:string,<br />
$put as function()<br />
) as item()*</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Retrieves an entry from the store with the given {{Code|$key}}. The {{Code|$put}} function will only be invoked if the entry does not exist, and its result will be stored and returned instead.<br />
|}<br />
<br />
==store:remove==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:remove(<br />
$key as xs:string<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Removes an entry with the given {{Code|$key}} from the store. No error will be raised if an addressed entry does not exist.<br />
|}<br />
<br />
==store:keys==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:keys() as xs:string*</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Lists the names of all keys.<br />
|}<br />
<br />
==store:clear==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:clear() as empty-sequence()</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Resets the store by removing all its entries.<br />
|}<br />
<br />
=Store Operations=<br />
<br />
==store:read==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:read(<br />
$name as xs:string? :=()<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Retrieves the standard store from disk, or a custom store if a {{Code|$name}} is supplied.<br />
|- valign="top"<br />
|'''Errors'''<br />
|{{Error|io|#Errors}} The store could not be read.<br/>{{Error|name|#Errors}} The specified name is invalid.<br/>{{Error|not-found|#Errors}} A store with the specified name does not exist.<br />
|}<br />
<br />
==store:write==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:write(<br />
$name as xs:string? :=()<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Writes the standard store to disk, or to a custom store file if a {{Code|$name}} is supplied. If the standard store is empty, the store file will be deleted.<br />
|- valign="top"<br />
|'''Errors'''<br />
|{{Error|io|#Errors}} The store could not be written.<br/>{{Error|name|#Errors}} The specified name is invalid.<br />
|}<br />
<br />
==store:list==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:list() as xs:string*</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Lists the names of all custom stores.<br />
|}<br />
<br />
==store:delete==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:delete(<br />
$name as xs:string<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Deletes a custom store from disk.<br />
|- valign="top"<br />
|'''Errors'''<br />
|{{Error|name|#Errors}} The specified name is invalid.<br/>{{Error|not-found|#Errors}} A store with the specified name does not exist.<br />
|}<br />
<br />
=Examples=<br />
<br />
'''Use Case 1: Create/update a system configuration in a running BaseX server instance:<br />
<br />
<syntaxhighlight lang="xquery"><br />
(: store an integer :)<br />
store:put('version', 1),<br />
(: retrieve existing or new value, store an element :)<br />
let $license := store:get-or-put('license', function() { 'free' })<br />
return store:put('info', <info>{ $license = 'free' ?? 'Free' !! 'Professional' } License</info>),<br />
(: store a map :)<br />
store:put('data', map { 'year': 2022 }),<br />
(: serialize configuration to disk :)<br />
store:write()<br />
</syntaxhighlight><br />
<br />
The configuration can be requested by further operations, e.g. a client request:<br />
<br />
<syntaxhighlight lang="xquery"><br />
store:get('version')<br />
</syntaxhighlight><br />
<br />
The store will still be available if BaseX is restarted until it is cleared.<br />
<br />
'''Use Case 2: Create index for fast lookup operations in the GUI:<br />
<br />
<syntaxhighlight lang="xquery"><br />
let $map := map:merge(<br />
for $country in db:get('factbook')//country<br />
for $religion in $country//religions<br />
group by $religion<br />
return map:entry($religion, data($country/@name))<br />
)<br />
return store:put('religions', $map)<br />
</syntaxhighlight><br />
<br />
A subsequent query can be used to access its contents:<br />
<br />
<syntaxhighlight lang="xquery"><br />
store:get('religions')?Buddhism<br />
</syntaxhighlight><br />
<br />
Note that the store will eventually be written to disk unless it is invalidated before closing the GUI.<br />
<br />
=Errors=<br />
<br />
{| class="wikitable" width="100%"<br />
! width="110"|Code<br />
|Description<br />
|- valign="top"<br />
|{{Code|io}}<br />
| The store could not be read or written.<br />
|- valign="top"<br />
|{{Code|name}}<br />
| The specified name is invalid.<br />
|- valign="top"<br />
|{{Code|not-found}}<br />
| A store with the specified name does not exist.<br />
|}<br />
<br />
=Changelog=<br />
<br />
The module was introduced with Version 10.</div>Andy Buncehttps://docs.basex.org/index.php?title=Update_Module&diff=16566Update Module2023-07-03T11:29:48Z<p>Andy Bunce: update:for-each sig add comma</p>
<hr />
<div>This [[Module Library|XQuery Module]] provides additional functions for performing updates and returning results in [[XQuery Update|updating expressions]].<br />
<br />
=Conventions=<br />
<br />
All functions in this module are assigned to the <code><nowiki>http://basex.org/modules/update</nowiki></code> namespace, which is statically bound to the {{Code|update}} prefix.<br/><br />
<br />
Except for {{Function||update:output-cache}}, all functions are ''updating'' and thus comply to the XQuery Update constraints.<br />
<br />
=Updates=<br />
<br />
==update:apply==<br />
<br />
{|<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>update:apply(<br />
$function as function(*),<br />
$arguments as array(*)<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|The updating variant of [[XQuery 3.1#fn:apply|fn:apply]] applies the specified updating <code>$function</code> to the specified <code>$arguments</code>.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* Creates a new database with an initial document and adds a document to an existing database.<br />
<syntaxhighlight lang="xquery"><br />
declare %updating function local:update(<br />
$database as xs:string,<br />
$path as xs:string,<br />
$function as %updating function(item(), xs:string) as empty-sequence()<br />
) as empty-sequence() {<br />
update:apply($function, [ $database, $path ])<br />
};<br />
local:update('new-db', 'doc.xml', db:create#2),<br />
local:update('existing-db', 'doc.xml', db:add#2)<br />
</syntaxhighlight><br />
|}<br />
<br />
==update:for-each==<br />
<br />
{|<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>update:for-each(<br />
$input as item()*,<br />
$action as function(item())<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|The updating variant of [[Higher-Order Functions#fn:for-each|fn:for-each]] applies the specified updating <code>$action</code> to every item of <code>$input</code>.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* Creates two databases:<br />
<syntaxhighlight lang="xquery"><br />
let $names := ('db1', 'db2')<br />
return update:for-each($names, db:create#1)<br />
</syntaxhighlight><br />
|}<br />
<br />
==update:for-each-pair==<br />
<br />
{|<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>update:for-each-pair(<br />
$input1 as item()*,<br />
$input2 as item()*,<br />
$action as function(item())<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|The updating variant of [[Higher-Order Functions#fn:for-each-pair|fn:for-each-pair]] applies the specified updating <code>$action</code> to the successive pairs of items of <code>$input1</code> and <code>$input2</code>. Evaluation is stopped if one sequence yields no more items.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* Renames nodes in an XML snippets:<br />
<syntaxhighlight lang="xquery"><br />
copy $xml := <xml><a/><b/></xml><br />
modify update:for-each-pair(<br />
('a', 'b'),<br />
('d', 'e'),<br />
function($source, $target) {<br />
for $e in $xml/*[name() = $source]<br />
return rename node $e as $target<br />
}<br />
)<br />
return $xml<br />
</syntaxhighlight><br />
|}<br />
<br />
==update:map-for-each==<br />
<br />
{| width='100%'<br />
| width='120' | '''Signature'''<br />
|<pre>update:map-for-each(<br />
$map as map(*),<br />
$action as function(xs:anyAtomicType, item()*) as item()*<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|The updating variant of {{Function|Map|map:for-each}} applies the specified {{Code|$action}} to every key/value pair of the supplied {{Code|$map}} and returns the results as a sequence.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* Inserts attributes into a document:<br />
<syntaxhighlight lang="xquery"><br />
copy $doc := <xml/><br />
modify update:map-for-each(<br />
map {<br />
'id': 'id0',<br />
'value': 456<br />
},<br />
function($key, $value) {<br />
insert node attribute { $key } { $value } into $doc<br />
}<br />
)<br />
return $doc</syntaxhighlight><br />
|}<br />
<br />
=Output=<br />
<br />
==update:output==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>update:output(<br />
$input as item()*<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|This function can be used if {{Option|MIXUPDATES}} is not enabled, and if values need to be returned within an updating expression: The supplied {{Code|$input}} will be cached and returned at the very end, i.e., after all updates on the ''pending update list'' have been processed. If one of the supplied items is affected by an update, a copy will be created and cached instead.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|update:output("Prices have been deleted."), delete node //price}} deletes all {{Code|price}} elements in a database and returns an info message.<br />
|}<br />
<br />
==update:cache==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>update:cache(<br />
$reset as xs:boolean? := false()<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the items that have been cached by {{Function||update:output}}. The output cache can optionally be {{Code|$reset}}. The function can be used to check which items will eventually be returned as the result of an updating function.<br/>This function is ''non-deterministic'': It will return different results before and after items have been cached. The function can be useful for writing [[Unit Module|unit tests]].<br />
|}<br />
<br />
=Changelog=<br />
<br />
;Version 9.3<br />
* {{Function||update:cache}}: {{code|$reset}} parameter added.<br />
<br />
;Version 9.1<br />
* {{Function||update:output}}: Maps and arrays can be cached if they contain no persistent database nodes or function items.<br />
<br />
;Version 9.0<br />
* Updated: db:output renamed to {{Function||update:output}}, db:output-cache renamed to {{Function||update:cache}}<br />
<br />
This module was introduced with Version 9.0.</div>Andy Buncehttps://docs.basex.org/index.php?title=Store_Module&diff=16565Store Module2023-07-03T11:27:50Z<p>Andy Bunce: store:get sig remove br</p>
<hr />
<div>This [[Module Library|XQuery Module]] provides functions to organize values in a persistent main-memory key-value store.<br />
<br />
The store is useful if data (a system configuration, maps serving as indexes) needs to be repeatedly accessed. The store is persistent: Contents will be written to disk at shutdown time, and the serialized store will be retrieved from disk as soon as the store is used for the first time. The store will be stored in a binary {{Code|store.basex}} file in the database directory.<br />
<br />
In addition, custom stores can be read and written. Custom stores have filenames with the pattern {{Code|store-NAME.basex}}. The implicit write of the standard store at shutdown time will be disabled if a custom store is used.<br />
<br />
Functions of this module are non-deterministic and side-effecting: Updates will immediately be visible, and a repeated call of the same function may yield different results if the contents of the store have changed.<br />
<br />
=Conventions=<br />
<br />
All functions and errors in this module are assigned to the <code><nowiki>http://basex.org/modules/store</nowiki></code> namespace, which is statically bound to the {{Code|store}} prefix.<br/><br />
<br />
=Key-value operations=<br />
<br />
==store:get==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:get(<br />
$key as xs:string<br />
) as item()*</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Retrieves an entry from the store with the given {{Code|$key}}. If the addressed entry does not exist, an empty sequence is returned.<br />
|}<br />
<br />
==store:put==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:put(<br />
$key as xs:string,<br />
$value as item()*<br />
) as empty-sequence()<br/ ></pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Stores an entry with the given {{Code|$key}} and {{Code|$value}} in the store:<br />
* If the value is an empty sequence, the entry is removed.<br />
* If a value refers to an opened database or is [[Lazy Module|a lazy item]], its contents are materialized in main memory.<br />
* Values with function items are rejected.<br />
|}<br />
<br />
==store:get-or-put==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:get-or-put(<br />
$key as xs:string,<br />
$put as function()<br />
) as item()*<br/ ></pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Retrieves an entry from the store with the given {{Code|$key}}. The {{Code|$put}} function will only be invoked if the entry does not exist, and its result will be stored and returned instead.<br />
|}<br />
<br />
==store:remove==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:remove(<br />
$key as xs:string<br />
) as empty-sequence()<br/ ></pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Removes an entry with the given {{Code|$key}} from the store. No error will be raised if an addressed entry does not exist.<br />
|}<br />
<br />
==store:keys==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:keys() as xs:string*</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Lists the names of all keys.<br />
|}<br />
<br />
==store:clear==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:clear() as empty-sequence()<br/ ></pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Resets the store by removing all its entries.<br />
|}<br />
<br />
=Store Operations=<br />
<br />
==store:read==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:read() as empty-sequence()<br/ >{{Func</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Retrieves the standard store from disk, or a custom store if a {{Code|$name}} is supplied.<br />
|- valign="top"<br />
|'''Errors'''<br />
|{{Error|io|#Errors}} The store could not be read.<br/>{{Error|name|#Errors}} The specified name is invalid.<br/>{{Error|not-found|#Errors}} A store with the specified name does not exist.<br />
|}<br />
<br />
==store:write==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:write() as empty-sequence()<br/ >{{Func</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Writes the standard store to disk, or to a custom store file if a {{Code|$name}} is supplied. If the standard store is empty, the store file will be deleted.<br />
|- valign="top"<br />
|'''Errors'''<br />
|{{Error|io|#Errors}} The store could not be written.<br/>{{Error|name|#Errors}} The specified name is invalid.<br />
|}<br />
<br />
==store:list==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:list() as xs:string*</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Lists the names of all custom stores.<br />
|}<br />
<br />
==store:delete==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>store:delete(<br />
$name as xs:string<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|Deletes a custom store from disk.<br />
|- valign="top"<br />
|'''Errors'''<br />
|{{Error|name|#Errors}} The specified name is invalid.<br/>{{Error|not-found|#Errors}} A store with the specified name does not exist.<br />
|}<br />
<br />
=Examples=<br />
<br />
'''Use Case 1: Create/update a system configuration in a running BaseX server instance:<br />
<br />
<syntaxhighlight lang="xquery"><br />
(: store an integer :)<br />
store:put('version', 1),<br />
(: retrieve existing or new value, store an element :)<br />
let $license := store:get-or-put('license', function() { 'free' })<br />
return store:put('info', <info>{ $license = 'free' ?? 'Free' !! 'Professional' } License</info>),<br />
(: store a map :)<br />
store:put('data', map { 'year': 2022 }),<br />
(: serialize configuration to disk :)<br />
store:write()<br />
</syntaxhighlight><br />
<br />
The configuration can be requested by further operations, e.g. a client request:<br />
<br />
<syntaxhighlight lang="xquery"><br />
store:get('version')<br />
</syntaxhighlight><br />
<br />
The store will still be available if BaseX is restarted until it is cleared.<br />
<br />
'''Use Case 2: Create index for fast lookup operations in the GUI:<br />
<br />
<syntaxhighlight lang="xquery"><br />
let $map := map:merge(<br />
for $country in db:get('factbook')//country<br />
for $religion in $country//religions<br />
group by $religion<br />
return map:entry($religion, data($country/@name))<br />
)<br />
return store:put('religions', $map)<br />
</syntaxhighlight><br />
<br />
A subsequent query can be used to access its contents:<br />
<br />
<syntaxhighlight lang="xquery"><br />
store:get('religions')?Buddhism<br />
</syntaxhighlight><br />
<br />
Note that the store will eventually be written to disk unless it is invalidated before closing the GUI.<br />
<br />
=Errors=<br />
<br />
{| class="wikitable" width="100%"<br />
! width="110"|Code<br />
|Description<br />
|- valign="top"<br />
|{{Code|io}}<br />
| The store could not be read or written.<br />
|- valign="top"<br />
|{{Code|name}}<br />
| The specified name is invalid.<br />
|- valign="top"<br />
|{{Code|not-found}}<br />
| A store with the specified name does not exist.<br />
|}<br />
<br />
=Changelog=<br />
<br />
The module was introduced with Version 10.</div>Andy Buncehttps://docs.basex.org/index.php?title=SQL_Module&diff=16564SQL Module2023-07-03T11:25:24Z<p>Andy Bunce: sql:connect sig remove br add options</p>
<hr />
<div>This [[Module Library|XQuery Module]] contains functions to access relational databases from XQuery using SQL. With this module, you can execute query, update and prepared statements, and the result sets are returned as sequences of XML elements representing tuples. Each element has children representing the columns returned by the SQL statement.<br />
<br />
This module uses JDBC to connect to a SQL server. Hence, your JDBC driver will need to be added to the classpath, too. If you work with the full distributions of BaseX, you can copy the driver into the {{Code|lib}} directory. To connect to MySQL, for example, download the [https://dev.mysql.com/downloads/connector/j/ Connector/J Driver] and extract the archive into this directory.<br />
<br />
=Conventions=<br />
<br />
All functions and errors in this module are assigned to the <code><nowiki>http://basex.org/modules/sql</nowiki></code> namespace, which is statically bound to the {{Code|sql}} prefix.<br/><br />
<br />
=Functions=<br />
<br />
==sql:init==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>sql:init(<br />
$class as xs:string<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|This function initializes a JDBC driver specified via {{Code|$class}}. This step might be superfluous if the SQL database is not embedded.<br/ ><br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|init|#Errors}} the specified driver is not found.<br />
|}<br />
<br />
==sql:connect==<br />
<br />
{{Announce|Updated with Version 11:}} Optional credentials.<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>sql:connect(<br />
$url as xs:string,<br />
$options as map(*)? := map { }<br />
) as xs:anyURI</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|This function establishes a connection to a relational database and returns a connection id. The parameter {{Code|$url}} is the URL of the database and shall be of the form: {{Code|jdbc:<driver name>:[//<server>[/<database>]]}}. Values specified for {{Code|$username}} and {{Code|$password}} are used as credentials for connecting to the database. The {{Code|$options}} parameter can be used to set connection options.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|error|#Errors}} an SQL exception occurred when connecting to the database.<br />
|- valign="top"<br />
| '''Examples'''<br />
|Connects to an SQL Server and sets autocommit to {{Code|true}}:<br />
<syntaxhighlight lang="xquery"><br />
sql:connect('dbc:sqlserver://DBServer', map { 'autocommit': true() })<br />
</syntaxhighlight><br />
|}<br />
<br />
==sql:execute==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>sql:execute(<br />
$id as xs:anyURI,<br />
$statement as xs:string,<br />
$options as map(*)? := map { }<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| This function executes an SQL {{Code|$statement}}, using the connection with the specified {{Code|$id}}. The returned result depends on the kind of statement:<br />
* If an update statement was executed, the number of updated rows will be returned as integer.<br />
* Otherwise, an XML representation of all results will be returned.<br />
With {{Code|$options}}, the following parameter can be set:<br />
* {{Code|timeout}}: query execution will be interrupted after the specified number of seconds.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|error|#Errors}} an error occurred while executing SQL.<br/ >{{Error|id|#Errors}} the specified connection does not exist.<br/>{{Error|timeout|#Errors}} query execution exceeded timeout.<br/><br />
|}<br />
<br />
==sql:execute-prepared==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>sql:execute-prepared(<br />
$id as xs:anyURI,<br />
$params as element(sql:parameters),<br />
$options as map(*)? := map { }<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| This function executes a prepared statement with the specified {{Code|$id}}. The output format is identical to {{Function||sql:execute}}. The optional parameter {{Code|$params}} is an element {{Code|<sql:parameters/>}} representing the parameters for a prepared statement along with their types and values. The following schema shall be used:<br/ ><br />
<syntaxhighlight lang="xquery"><br />
element sql:parameters {<br />
element sql:parameter {<br />
attribute type { "bigdecimal" | "boolean" | "byte" | "date" | "double" | "float" |<br />
"int" | "long" | "short" | "sqlxml" | "string" | "time" | "timestamp" },<br />
attribute null { "true" | "false" }?,<br />
text<br />
}+<br />
}?<br />
</syntaxhighlight><br />
With {{Code|$options}}, the following parameter can be set:<br />
* {{Code|timeout}}: query execution will be interrupted after the specified number of seconds.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|attribute|#Errors}} an attribute different from {{Code|type}} and {{Code|null}} is set for a {{Code|<sql:parameter/>}} element.<br/ >{{Error|error|#Errors}} an error occurred while executing SQL.<br/ >{{Error|id|#Errors}} the specified connection does not exist.<br/ >{{Error|parameters|#Errors}} no parameter type specified.<br/>{{Error|timeout|#Errors}} query execution exceeded timeout.<br/>{{Error|type|#Errors}} the value of a parameter cannot be converted to the specified format.<br />
|}<br />
<br />
==sql:prepare==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>sql:prepare(<br />
$id as xs:anyURI,<br />
$statement as xs:string<br />
) as xs:anyURI</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|This function prepares an SQL {{Code|$statement}}, using the specified connection {{Code|$id}}, and returns the id reference to this statement. The statement is a string with one or more '?' placeholders. If the value of a field has to be set to {{Code|NULL}}, then the attribute {{Code|null}} of the {{Code|<sql:parameter/>}} element must be {{Code|true}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|error|#Errors}} an error occurred while executing SQL.<br/ >{{Error|id|#Errors}} the specified connection does not exist.<br/ ><br />
|}<br />
<br />
==sql:commit==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>sql:commit(<br />
$id as xs:anyURI<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| This function commits the changes made to a relational database, using the specified connection {{Code|$id}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|error|#Errors}} an error occurred while executing SQL.<br/ >{{Error|id|#Errors}} the specified connection does not exist.<br/ ><br />
|}<br />
<br />
==sql:rollback==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>sql:rollback(<br />
$id as xs:anyURI<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| This function rolls back the changes made to a relational database, using the specified connection {{Code|$id}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|error|#Errors}} an error occurred while executing SQL.<br/ >{{Error|id|#Errors}} the specified connection does not exist.<br/ ><br />
|}<br />
<br />
==sql:close==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>sql:close(<br />
$id as xs:anyURI<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| This function closes a database connection with the specified {{Code|$id}}.<br/>Opened connections will automatically be closed after the XQuery expression has been evaluated, but in order to save memory, it is always recommendable to close connections that are not used anymore.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|error|#Errors}} an error occurred while executing SQL.<br/ >{{Error|id|#Errors}} the specified connection does not exist.<br/ ><br />
|}<br />
<br />
=Examples=<br />
<br />
==Direct queries==<br />
<br />
A simple select statement can be executed as follows:<br />
<br />
<syntaxhighlight lang="xquery"><br />
let $id := sql:connect("jdbc:postgresql://localhost:5432/coffeehouse")<br />
return sql:execute($id, "SELECT * FROM coffees WHERE price < 10")<br />
</syntaxhighlight><br />
<br />
The result may look like:<br />
<br />
<syntaxhighlight lang="xml"><br />
<sql:row xmlns:sql="http://basex.org/modules/sql"><br />
<sql:column name="cof_name">French_Roast</sql:column><br />
<sql:column name="sup_id">49</sql:column><br />
<sql:column name="price">3.5</sql:column><br />
<sql:column name="sales">15</sql:column><br />
<sql:column name="total">30</sql:column><br />
</sql:row><br />
<sql:row xmlns:sql="http://basex.org/modules/sql"><br />
<sql:column name="cof_name">French_Roast_Decaf</sql:column><br />
<sql:column name="sup_id">49</sql:column><br />
<sql:column name="price">7.5</sql:column><br />
<sql:column name="sales">10</sql:column><br />
<sql:column name="total">14</sql:column><br />
</sql:row><br />
</syntaxhighlight><br />
<br />
==Prepared Statements==<br />
<br />
A prepared select statement can be executed in the following way:<br />
<br />
<syntaxhighlight lang="xquery"><br />
(: Establish a connection :)<br />
let $conn := sql:connect("jdbc:postgresql://localhost:5432/coffeehouse")<br />
(: Obtain a handle to a prepared statement :)<br />
let $prep := sql:prepare($conn, "SELECT * FROM coffees WHERE price < ? AND cof_name = ?")<br />
(: Values and types of prepared statement parameters :)<br />
let $params := <sql:parameters><br />
<sql:parameter type='double'>10</sql:parameter><br />
<sql:parameter type='string'>French_Roast</sql:parameter><br />
</sql:parameters><br />
(: Execute prepared statement :)<br />
return sql:execute-prepared($prep, $params)<br />
</syntaxhighlight><br />
<br />
==SQLite==<br />
<br />
The following expression demonstrates how SQLite can be addressed with the [https://bitbucket.org/xerial/sqlite-jdbc/ Xerial SQLite JDBC driver]:<br />
<br />
<syntaxhighlight lang="xquery"><br />
(: Initialize driver :)<br />
sql:init("org.sqlite.JDBC"),<br />
(: Establish a connection :)<br />
let $conn := sql:connect("jdbc:sqlite:database.db")<br />
return (<br />
(: Create a new table :)<br />
sql:execute($conn, "drop table if exists person"),<br />
sql:execute($conn, "create table person (id integer, name string)"),<br />
(: Run 10 updates :)<br />
for $i in 1 to 10<br />
let $q := "insert into person values(" || $i || ", '" || $i || "')"<br />
return sql:execute($conn, $q),<br />
(: Return table contents :)<br />
sql:execute($conn, "select * from person")<br />
)<br />
</syntaxhighlight><br />
<br />
=Errors=<br />
<br />
{| class="wikitable" width="100%"<br />
! width="110"|Code<br />
|Description<br />
|- valign="top"<br />
|{{Code|attribute}}<br />
|An attribute different from {{Code|type}} and {{Code|null}} is set for a {{Code|&lt;sql:parameter/&gt;}} element.<br />
|- valign="top"<br />
|{{Code|error}}<br />
|An SQL exception occurred.<br />
|- valign="top"<br />
|{{Code|id}}<br />
|A connection does not exist.<br />
|- valign="top"<br />
|{{Code|init}}<br />
|A database driver is not found.<br />
|- valign="top"<br />
|{{Code|parameters}}<br />
|No parameter type specified.<br />
|- valign="top"<br />
|{{Code|timeout}}<br />
|Query execution exceeded timeout.<br />
|- valign="top"<br />
|{{Code|type}}<br />
|The value of a parameter cannot be converted to the specified format.<br />
|}<br />
<br />
=Changelog=<br />
<br />
;Version 11<br />
* Updated: {{Function||sql:connect}}: Optional credentials.<br />
<br />
;Version 9.6<br />
* Updated: {{Function||sql:execute-prepared}}, additional types added<br />
<br />
;Version 9.0<br />
* Updated: {{Function||sql:execute}}, {{Function||sql:execute-prepared}}: Return update count for updating statements. {{Code|$options}} argument added.<br />
* Updated: Connection ids are URIs now.<br />
* Updated: error codes updated; errors now use the module namespace<br />
<br />
;Version 7.5<br />
* Updated: prepared statements are now executed via {{Function||sql:execute-prepared}}<br />
<br />
The module was introduced with Version 7.0.</div>Andy Buncehttps://docs.basex.org/index.php?title=JSON_Module&diff=16563JSON Module2023-07-03T11:17:48Z<p>Andy Bunce: json:serialize signature add comma</p>
<hr />
<div>This [[Module Library|XQuery Module]] contains functions to parse and serialize JSON data [https://www.json.org/ JSON (JavaScript Object Notation)] is a popular data exchange format for applications written in JavaScript. As there are notable differences between JSON and XML, or XQuery data types, no mapping exists that guarantees a lossless, bidirectional conversion between JSON and XML. For this reason, we offer various mappings, all of which are suited to different use cases.<br />
<br />
=Conventions=<br />
<br />
All functions and errors in this module are assigned to the <code><nowiki>http://basex.org/modules/json</nowiki></code> namespace, which is statically bound to the {{Code|json}} prefix.<br/><br />
<br />
==Conversion Formats==<br />
<br />
'''A little advice''': in the Database Creation dialog of the GUI, if you select JSON Parsing and switch to the ''Parsing'' tab, you can see the effects of some of the conversion options.<br />
<br />
===Direct===<br />
<br />
The {{Code|direct}} conversion format allows a lossless conversion from JSON to XML and back. The transformation is based on the following rules:<br />
<br />
* The resulting document has a {{Code|json}} root node. <br />
* Object pairs are represented via elements. The name of a pair is encoded, as described in the [[Conversion Module#Keys|Conversion Module]], and used as element name.<br />
* Array entries are also represented via elements, with {{Code|_}} as element name.<br />
* Object and array values are stored in text nodes.<br />
* The types of values are represented via {{Code|type}} attributes:<br />
** The existing types are ''string'', ''number'', ''boolean'', ''null'', ''object'', and ''array''.<br />
** As most values are strings, the ''string'' type is by default omitted.<br />
<br />
===Attributes===<br />
<br />
The {{Code|attributes}} format is lossless, too. The transformation based on the following rules:<br />
<br />
* The resulting document has a {{Code|json}} root node. <br />
* Object pairs are represented via {{Code|pair}} elements. The name of a pair is stored in a {{Code|name}} attribute.<br />
* Array entries are represented via {{Code|item}} elements.<br />
* Object and array values are stored in text nodes.<br />
* The types of values are represented via {{Code|type}} attributes:<br />
** The existing types are ''string'', ''number'', ''boolean'', ''null'', ''object'', and ''array''.<br />
** As most values are strings, the ''string'' type is by default omitted.<br />
<br />
===Basic===<br />
<br />
The {{Code|basic}} format is another lossless format. It converts a JSON document to an XML node and vice versa. The conversion rules are the same as for [[XQuery 3.1#fn:json-to-xml|fn:json-to-xml]].<br />
<br />
===JsonML===<br />
<br />
The {{Code|jsonml}} format is designed to convert XML to JSON and back, using the JsonML dialect. JsonML allows the transformation of arbitrary XML documents, but namespaces, comments and processing instructions will be discarded in the transformation process. More details are found in the official [http://jsonml.org/XML JsonML documentation].<br />
<br />
===XQuery===<br />
<br />
The {{Code|xquery}} format is lossless, too. It converts JSON data to an XQuery value (a map, array, string, number, boolean, or empty sequence) and vice versa. The conversion rules are the same as for [[XQuery 3.1#fn:parse-json|fn:parse-json]].<br />
<br />
The resulting representation consumes less memory than XML-based formats, and values can be directly accessed without conversion. Thus, it is recommendable for very large inputs and for efficient ad-hoc processing.<br />
<br />
==Options==<br />
<br />
The following options are available (the ''Direction'' column indicates if an option applies to parsing, serialization, or both operations):<br />
<br />
{| class="wikitable sortable" width="100%"<br />
|- valign="top"<br />
! width="140" | Option<br />
! width="50%" | Description<br />
! Allowed<br />
! Default<br />
! Direction<br />
|- valign="top"<br />
| {{Code|format}}<br />
| Specifies the format for converting JSON data ([[#Conversion Formats|see above]]).<br />
| {{Code|direct}}, {{Code|attributes}}, {{Code|basic}}, {{Code|jsonml}}, {{Code|xquery}}<br />
| {{Code|direct}}<br />
| ''parse'', ''serialize''<br />
|- valign="top"<br />
| {{Code|liberal}}<br />
| Determines if minor deviations from [https://www.rfc-editor.org/rfc/rfc7159.txt RFC 7159] will be ignored.<br />
| {{Code|yes}}, {{Code|no}}<br />
| {{Code|no}}<br />
| ''parse''<br />
|- valign="top"<br />
| {{Code|merge}}<br />
| This option is considered when {{Code|direct}} or {{Code|attributes}} conversion is used:<br/><br />
* If a name has the same type throughout the data, the {{Code|type}} attribute will be omitted. Instead, the name will be listed in additional, type-specific attributes in the root node.<br />
* The attributes are named by their type in plural (''numbers'', ''booleans'', ''nulls'', ''objects'' and ''arrays''), and the attribute value contains all names with that type, separated by whitespaces.<br />
| {{Code|yes}}, {{Code|no}}<br />
| {{Code|no}}<br />
| ''parse'', ''serialize''<br />
|- valign="top"<br />
| {{Code|strings}}<br />
| Indicates if {{Code|type}} attributes will be added for strings.<br />
| {{Code|yes}}, {{Code|no}}<br />
| {{Code|yes}}<br />
| ''parse'', ''serialize''<br />
|- valign="top"<br />
| {{Code|lax}}<br />
| Specifies if [[Conversion Module#Keys|lax conversion rules]] are used to convert QNames to JSON names.<br />
| {{Code|yes}}, {{Code|no}}<br />
| {{Code|no}}<br />
| ''parse'', ''serialize''<br />
|- valign="top"<br />
| {{Code|escape}}<br />
| Indicates if escaped characters are expanded (for example, {{Code|\n}} becomes a single {{Code|x0A}} character, while {{Code|\u20AC}} becomes the character {{Code|€}}).<br />
| {{Code|yes}}, {{Code|no}}<br />
| {{Code|yes}}<br />
| ''parse''<br />
|- valign="top"<br />
| {{Code|escape}}<br />
| Indicates if characters are escaped whenever the JSON syntax requires it. This option can be set to {{Code|no}} if strings are already in escaped form and no further escaping is permitted.<br />
| {{Code|yes}}, {{Code|no}}<br />
| {{Code|yes}}<br />
| ''serialize''<br />
|- valign="top"<br />
| {{Code|indent}}<br />
| Indicates if whitespace should be added to the output with the aim of improving human legibility. If the parameter is set as in the query prolog, it overrides the {{Code|indent}} [[Serialization|serialization parameter]].<br />
| {{Code|yes}}, {{Code|no}}<br />
| {{Code|no}} {{Announce|Default changed with Version 10}}<br />
| ''serialize''<br />
|}<br />
<br />
=Functions=<br />
<br />
==json:doc==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>json:doc(<br />
$href as xs:string,<br />
$options as map(*)? := map { }<br />
) as item()?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Fetches the JSON document referred to by the given {{Code|$href}} and converts it to an XQuery value. The {{Code|$options}} argument can be used to control the way the input is converted.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|parse|#Errors}} the specified input cannot be parsed as JSON document.<br/>{{Error|options|#Errors}} the specified options are conflicting.<br />
|}<br />
<br />
==json:parse==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>json:parse(<br />
$value as xs:string?,<br />
$options as map(*)? := map { }<br />
) as item()?</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Converts the JSON {{Code|$value}} to an XQuery value. If the input can be successfully parsed, it can be serialized back to the original JSON representation. The {{Code|$options}} argument can be used to control the way the input is converted.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|parse|#Errors}} the specified input cannot be parsed as JSON document.<br/>{{Error|options|#Errors}} the specified options are conflicting.<br />
|}<br />
<br />
==json:serialize==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>json:serialize(<br />
$input as item()?,<br />
$options as map(*)? := map { }<br />
) as xs:string</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Serializes the specified {{Code|$input}} as JSON, using the specified {{Code|$options}}, and returns the result as string:<br />
* The input is expected to conform to the results that are created by {{Function||json:parse}}.<br />
* Non-conforming items will be serialized as specified in the [[XQuery 3.1#JSON Serialization|json output method]] of the official recommendation.<br />
Values can also be serialized as JSON with the standard [[Serialization]] feature of XQuery:<br />
* The parameter {{Code|method}} needs to be set to {{Code|json}}, and<br />
* the options presented in this article need to be assigned to the {{Code|json}} parameter.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|serialize|#Errors}} the specified node cannot be serialized as JSON document.<br />
|}<br />
<br />
=Examples=<br />
<br />
==BaseX Format==<br />
<br />
'''Example 1: Adds all JSON documents in a directory to a database'''<br />
<br />
'''Query:'''<br />
<syntaxhighlight lang="xquery"><br />
let $database := "database"<br />
for $name in file:list('.', false(), '*.json')<br />
let $file := file:read-text($name)<br />
let $json := json:parse($file)<br />
return db:add($database, $json, $name) <br />
</syntaxhighlight><br />
<br />
'''Example 2: Converts a simple JSON string to XML and back'''<br />
<br />
'''Query:'''<br />
<syntaxhighlight lang="xquery"><br />
json:parse('{}')<br />
</syntaxhighlight><br />
<br />
'''Result:'''<br />
<syntaxhighlight lang="xml"><br />
<json type="object"/><br />
</syntaxhighlight><br />
<br />
'''Query:'''<br />
<syntaxhighlight lang="xquery"><br />
(: serialize result as plain text :)<br />
declare option output:method 'text';<br />
json:serialize(<json type="object"/>)<br />
</syntaxhighlight><br />
<br />
'''Result:'''<br />
<syntaxhighlight lang="xquery"><br />
{ }<br />
</syntaxhighlight><br />
<br />
'''Example 3: Converts a JSON string with simple objects and arrays'''<br />
<br />
'''Query:'''<br />
<syntaxhighlight lang="xquery"><br />
json:parse('{<br />
"title": "Talk On Travel Pool",<br />
"link": "http://www.flickr.com/groups/talkontravel/pool/",<br />
"description": "Travel and vacation photos from around the world.",<br />
"modified": "2014-02-02T11:10:27Z",<br />
"generator": "http://www.flickr.com/"<br />
}')<br />
</syntaxhighlight><br />
<br />
'''Result:'''<br />
<syntaxhighlight lang="xml"><br />
<json type="object"><br />
<title>Talk On Travel Pool</title><br />
<link>http://www.flickr.com/groups/talkontravel/pool/</link><br />
<description>Travel and vacation photos from around the world.</description><br />
<modified>2014-02-02T11:10:27Z</modified><br />
<generator>http://www.flickr.com/</generator><br />
</json><br />
</syntaxhighlight><br />
<br />
'''Example 4: Converts a JSON string with different data types'''<br />
<br />
'''Query:'''<br />
<syntaxhighlight lang="xquery"><br />
let $options := map { 'merge': true() }<br />
return json:parse('{<br />
"first_name": "John",<br />
"last_name": "Smith",<br />
"age": 25,<br />
"address": {<br />
"street": "21 2nd Street",<br />
"city": "New York",<br />
"code": 10021<br />
},<br />
"phone": [<br />
{<br />
"type": "home",<br />
"number": "212 555-1234"<br />
},<br />
{<br />
"type": "mobile",<br />
"number": 1327724623<br />
}<br />
]<br />
}', $options)<br />
</syntaxhighlight><br />
<br />
'''Result:'''<br />
<syntaxhighlight lang="xml"><br />
<json numbers="age code" arrays="phone" objects="json address value"><br />
<first__name>John</first__name><br />
<last__name>Smith</last__name><br />
<age>25</age><br />
<address><br />
<street>21 2nd Street</street><br />
<city>New York</city><br />
<code>10021</code><br />
</address><br />
<phone><br />
<_><br />
<type>home</type><br />
<number>212 555-1234</number><br />
</_><br />
<_><br />
<type>mobile</type><br />
<number type="number">1327724623</number><br />
</_><br />
</phone><br />
</json><br />
</syntaxhighlight><br />
<br />
==JsonML Format==<br />
<br />
'''Example 1: Converts all XML documents in a database to the JsonML format and writes them to disk'''<br />
<br />
'''Query:'''<br />
<syntaxhighlight lang="xquery"><br />
for $doc in collection('json')<br />
let $name := document-uri($doc)<br />
let $json := json:serialize($doc, map { 'format': 'jsonml' })<br />
return file:write($name, $json)<br />
</syntaxhighlight><br />
<br />
'''Example 2: Converts an XML document with elements and text'''<br />
<br />
'''Query:'''<br />
<syntaxhighlight lang="xquery"><br />
json:serialize(doc('flickr.xml'), map { 'format': 'jsonml' })<br />
</syntaxhighlight><br />
<br />
'''flickr.xml:'''<br />
<syntaxhighlight lang="xml"><br />
<flickr><br />
<title>Talk On Travel Pool</title><br />
<link>http://www.flickr.com/groups/talkontravel/pool/</link><br />
<description>Travel and vacation photos from around the world.</description><br />
<modified>2014-02-02T11:10:27Z</modified><br />
<generator>http://www.flickr.com/</generator><br />
</flickr><br />
</syntaxhighlight><br />
<br />
'''Result:'''<br />
<syntaxhighlight lang="json"><br />
["flickr",<br />
["title",<br />
"Talk On Travel Pool"],<br />
["link",<br />
"http://www.flickr.com/groups/talkontravel/pool/"],<br />
["description",<br />
"Travel and vacation photos from around the world."],<br />
["modified",<br />
"2014-02-02T11:10:27Z"],<br />
["generator",<br />
"http://www.flickr.com/"]]<br />
</syntaxhighlight><br />
<br />
'''Example 3: Converts a document with nested elements and attributes to JsonML'''<br />
<br />
'''Query:'''<br />
<syntaxhighlight lang="xquery"><br />
json:serialize(doc('input.xml'), map { 'format': 'jsonml' })<br />
</syntaxhighlight><br />
<br />
'''input.xml:'''<br />
<syntaxhighlight lang="xml"><br />
<address id='1'><br />
<!-- comments will be discarded --><br />
<last_name>Smith</last_name><br />
<age>25</age><br />
<address xmlns='will be dropped as well'><br />
<street>21 2nd Street</street><br />
<city>New York</city><br />
<code>10021</code><br />
</address><br />
<phone type='home'>212 555-1234</phone><br />
</address><br />
</syntaxhighlight><br />
<br />
'''Result:'''<br />
<syntaxhighlight lang="json"><br />
["address", {"id":"1"},<br />
["last_name",<br />
"Smith"],<br />
["age",<br />
"25"],<br />
["address",<br />
["street",<br />
"21 2nd Street"],<br />
["city",<br />
"New York"],<br />
["code",<br />
"10021"]],<br />
["phone", {"type":"home"},<br />
"212 555-1234"]]<br />
</syntaxhighlight><br />
<br />
==XQuery Format==<br />
<br />
'''Example 1: Converts a JSON string to XQuery'''<br />
<br />
'''Query:'''<br />
<syntaxhighlight lang="xquery"><br />
let $input := '{<br />
"Title": "Drinks",<br />
"Author": [ "Jim Daniels", "Jack Beam" ]<br />
}'<br />
let $data := json:parse($input, map { 'format': 'xquery' })<br />
return map:for-each($data, function($k, $v) {<br />
$k || ': ' || string-join($v, ', ')<br />
})<br />
</syntaxhighlight><br />
<br />
'''Result:'''<br />
<syntaxhighlight lang="json"><br />
Author: Jim Daniels, Jack Beam<br />
Title: Drinks<br />
</syntaxhighlight><br />
<br />
'''Example 2: Converts XQuery data to JSON'''<br />
<br />
'''Query:'''<br />
<syntaxhighlight lang="xquery"><br />
for $item in (<br />
true(),<br />
'ABC',<br />
array { 1 to 5 },<br />
map { "Key": "Value" }<br />
)<br />
return json:serialize(<br />
$item,<br />
map { 'format': 'xquery', 'indent': 'no' }<br />
)<br />
</syntaxhighlight><br />
<br />
'''Result:'''<br />
<syntaxhighlight lang="json"><br />
true<br />
"ABC"<br />
[1,2,3,4,5]<br />
{"Key":"Value"}<br />
</syntaxhighlight><br />
<br />
=Errors=<br />
<br />
{| class="wikitable" width="100%"<br />
! width="110"|Code<br />
|Description<br />
|- valign="top"<br />
|{{Code|options}}<br />
|The specified options are conflicting.<br />
|- valign="top"<br />
|{{Code|parse}}<br />
|The specified input cannot be parsed as JSON document.<br />
|- valign="top"<br />
|{{Code|serialize}}<br />
|The specified node cannot be serialized as JSON document.<br />
|}<br />
<br />
=Changelog=<br />
<br />
;Version 10.0<br />
* Updated: {{Code|indent}}: Default changed from {{Code|yes}} to {{Code|no}}.<br />
<br />
;Version 9.4<br />
* Added: {{Function||json:doc}}<br />
<br />
; Version 9.1<br />
* Updated: {{Function||json:parse}} can be called with empty sequence.<br />
<br />
;Version 9.0<br />
* Updated: <code>map</code> format renamed to <code>xquery</code>.<br />
* Updated: error codes updated; errors now use the module namespace<br />
<br />
;Version 8.4<br />
* Updated: <code>unescape</code> changed to <code>escape</code>.<br />
<br />
;Version 8.2<br />
* Added: Conversion format <code>[[#Basic|basic]]</code>.<br />
<br />
;Version 8.0<br />
* Updated: Serialization aligned with the {{Code|json}} output method of the official specification.<br />
* Added: {{Code|liberal}} option.<br />
* Removed: {{Code|spec}} option.<br />
<br />
;Version 7.8<br />
* Removed: {{Code|json:parse-ml}}, {{Code|json:serialize-ml}}.<br />
* Updated: {{Code|json:parse}} now returns a document node instead of an element, or an XQuery map if {{Code|format}} is set to {{Code|.map}}.<br />
<br />
;Version 7.7.2<br />
* Updated: {{Code|$options}} argument added to {{Function||json:parse}} and {{Function||json:serialize}}.<br />
* Updated: {{Function||json:parse-ml}} and {{Function||json:serialize-ml}} are now ''deprecated''.<br />
<br />
The module was introduced with Version 7.0.</div>Andy Buncehttps://docs.basex.org/index.php?title=Client_Module&diff=16562Client Module2023-07-03T11:11:52Z<p>Andy Bunce: client:connect remove <br/></p>
<hr />
<div>This [[Module Library|XQuery Module]] contains functions to access BaseX server instances from XQuery. With this module, you can execute database commands and evaluate XQuery expressions.<br />
<br />
Please note that the client module should always be used to address independent BaseX server instances. You can create deadlocks if you evaluate a query with a server instance, and if you are addressing the same server instance in your query. See the following example:<br />
<br />
<syntaxhighlight lang="xquery"><br />
(: Retrieve documents from database :)<br />
let $client-id := client:connect('localhost', 1984, 'admin', '...')<br />
let $docs := client:query($client-id, 'db:get("conflict")')<br />
(: Create database with same name :)<br />
return db:create('conflict', $docs, $docs ! db:path(.)) <br />
</syntaxhighlight><br />
<br />
The read-only query cannot be processed, because the <code>conflict</code> database is currently write-locked by the main query. See [[Transaction Management]] for more background information.<br />
<br />
=Conventions=<br />
<br />
All functions and errors in this module are assigned to the <code><nowiki>http://basex.org/modules/client</nowiki></code> namespace, which is statically bound to the {{Code|client}} prefix.<br/><br />
<br />
=Functions=<br />
<br />
==client:connect==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>client:connect(<br />
$host as xs:string,<br />
$port as xs:integer,<br />
$username as xs:string,<br />
$password as xs:string<br />
) as xs:anyURI</pre><br />
|- valign="top"<br />
|'''Summary'''<br />
|This function establishes a connection to a remote BaseX server, creates a new client session, and returns a session id. The parameter {{Code|$host}} is the name of the database server, {{Code|$port}} specifies the server port, and {{Code|$username}} and {{Code|$password}} represent the login data.<br />
|- valign="top"<br />
|'''Errors'''<br />
|{{Error|connect|#Errors}} an error occurs while creating the session (possible reasons: server not available, access denied).<br/><br />
|}<br />
<br />
==client:execute==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>client:execute(<br />
$id as xs:anyURI,<br />
$command as xs:string<br />
) as xs:string</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| This function executes a [[Commands|command]] and returns the result as a string. The parameter {{Code|$id}} contains the session ID returned by {{Function||client:connect}}. The {{Code|$command}} argument represents a single command, which will be executed by the server.<br />
|- valign="top"<br />
|'''Errors'''<br />
|{{Error|error|#Errors}} an I/O error occurs while transferring data from or to the server.<br/>{{Error|command|#Errors}} an error occurs while executing a command.<br />
|- valign="top"<br />
| '''Examples'''<br />
|The following query creates a new database {{Code|TEST}} on a remote BaseX server:<br />
<syntaxhighlight lang="xquery"><br />
client:connect('basex.server.org', 8080, 'admin', '...') !<br />
client:execute(., 'create database TEST')<br />
</syntaxhighlight><br />
|}<br />
<br />
==client:info==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>client:info(<br />
$id as xs:anyURI<br />
) as xs:string</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| This function returns an information string, created by the last call of {{Function||client:execute}}. {{Code|$id}} specifies the session id.<br />
|}<br />
<br />
==client:query==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>client:query(<br />
$id as xs:anyURI,<br />
$query as xs:string,<br />
$bindings as map(*)? := ()<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Evaluates a query and returns the result as sequence. The parameter {{Code|$id}} contains the session id returned by {{Function||client:connect}}, and {{Code|$query}} represents the query string, which will be evaluated by the server.<br/>Variables and the context item can be declared via {{Code|$bindings}}. The specified keys must be QNames or strings:<br />
* If a key is a QName, it will be directly adopted as variable name.<br />
* If a key is a string, it may be prefixed with a dollar sign. A namespace can be specified using the [http://www.jclark.com/xml/xmlns.htm Clark Notation]. If the specified string is empty, the value will be bound to the context item.<br />
|- valign="top"<br />
|'''Errors'''<br />
|{{Error|error|#Errors}} an I/O error occurs while transferring data from or to the server.<br/>{{Error|query|#Errors}} an error occurs while evaluating a query, and if the original error cannot be extracted from the returned error string.<br/>{{Error|function|#Errors}} function items (including maps and arrays) cannot be returned.<br />
|- valign="top"<br />
| '''Examples'''<br />
|The following query sends a query on a local server instance, binds the integer {{Code|123}} to the variable {{Code|$n}} and returns {{Code|246}}:<br />
<syntaxhighlight lang="xquery"><br />
let $c := client:connect('localhost', 1984, 'admin', '...')<br />
return client:query($c, "declare variable $n external; $n * 2", map { 'n': 123 })<br />
</syntaxhighlight><br />
The following query performs a query on a first server, the results of which are passed on to a second server:<br />
<syntaxhighlight lang="xquery"><br />
let $c1 := client:connect('basex1.server.org', 8080, 'jack', 'C0S19tt2X')<br />
let $c2 := client:connect('basex2.server.org', 8080, 'john', '465wFHe26')<br />
for $it in client:query($c1, '1 to 10')<br />
return client:query($c2, $it || '* 2')<br />
</syntaxhighlight><br />
|}<br />
<br />
==client:close==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>client:close(<br />
$id as xs:anyURI<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
| This function closes a client session. {{Code|$id}} specifies the session id.<br/>Opened connections will automatically be closed after the XQuery expression has been evaluated, but it is recommendable to explicitly close them with this function if you open many connections.<br />
|- valign="top"<br />
|'''Errors'''<br />
|{{Error|error|#Errors}} an I/O error occurs while transferring data from or to the server.<br />
|}<br />
<br />
=Errors=<br />
<br />
{| class="wikitable" width="100%"<br />
! width="110"|Code<br />
|Description<br />
|- valign="top"<br />
|{{Code|command}}<br />
| An error occurred while executing a command.<br />
|- valign="top"<br />
|{{Code|connect}}<br />
| An error occurred while creating a new session (possible reasons: server not available, access denied).<br />
|- valign="top"<br />
|{{Code|error}}<br />
| An I/O error occurred while transferring data from or to the server.<br />
|- valign="top"<br />
|{{Code|function}}<br />
| Function items (including maps and arrays) cannot be returned.<br />
|- valign="top"<br />
|{{Code|id}}<br />
| The id with the specified session is unknown, or has already been closed.<br />
|- valign="top"<br />
|{{Code|query}}<br />
| An error occurred while evaluating a query. Will only be raised if the XQuery error cannot be extracted from the returned error string.<br />
|}<br />
<br />
=Changelog=<br />
<br />
;Version 9.0<br />
<br />
* Updated: error codes updated; errors now use the module namespace<br />
<br />
;Version 8.0<br />
<br />
* Updated: Bound values may now contain no or more than one item in {{Function||client:query}}.<br />
<br />
;Version 7.5<br />
<br />
* Added: {{Function||client:info}}<br />
<br />
The module was introduced with Version 7.3.</div>Andy Buncehttps://docs.basex.org/index.php?title=Database_Module&diff=16527Database Module2023-03-22T10:50:06Z<p>Andy Bunce: fix margins on db:list summary</p>
<hr />
<div>This [[Module Library|XQuery Module]] contains functions for processing databases from within XQuery. Existing databases can be opened and listed, its contents can be directly accessed, documents can be added to and removed, etc.<br />
<br />
=Conventions=<br />
<br />
All functions and errors in this module are assigned to the <code><nowiki>http://basex.org/modules/db</nowiki></code> namespace, which is statically bound to the {{Code|db}} prefix.<br/><br />
<br />
==Database Nodes==<br />
<br />
In BaseX, two internal representations exist for nodes.<br />
<br />
* XML fragments are generated by XQuery node constructors.db:b<br />
* Database nodes are:<br />
** stored in a persistent database on disk;<br />
** nodes of a document that has been generated temporarily with {{Code|fn:doc}}, {{Code|fn:parse-xml}} and other functions; or<br />
** result of a main-memory update operation.<br />
<br />
Some operations are restricted to database nodes, but you can convert XML fragments to database nodes by applying an empty [[XQuery_Update#update|update]] or [[XQuery_Update#transform|transform]] operation to a node. Two examples:<br />
<br />
* Retrieve the internal node id of an XML fragment:<br />
<br />
<syntaxhighlight lang="xquery"><br />
let $xml := <xml>hello world</xml> update {}<br />
return db:node-id($xml/text())<br />
</syntaxhighlight><br />
<br />
* Puts a marker element around the result of a full-text request (see {{Function|Full-Text|ft:mark}} for more details):<br />
<br />
<syntaxhighlight lang="xquery"><br />
copy $p := <xml>hello world</xml><br />
modify ()<br />
return ft:mark($p[text() contains text 'word'], 'b')<br />
</syntaxhighlight><br />
<br />
==Updating Functions==<br />
<br />
Various functions in this module are ''updating''. Updating functions will not be immediately executed, but queued on the [[XQuery Update#Pending Update List|Pending Update List]], and processed after the remaining query has been evaluated. This means that the order in which the functions are specified in the query often does not reflect the order in which they will eventually be executed.<br />
<br />
=General Functions=<br />
<br />
==db:system==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:system() as element(system)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns general information on the database system the current values of all global and local [[Options]]. The {{Command|INFO}} command returns similar output.<br />
|}<br />
<br />
==db:option==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:option(<br />
$name as xs:string<br />
) as xs:string</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the current value (string, integer, boolean, map) of a global or local [[Options|Option]] with the specified {{Code|$name}}. The {{Command|SHOW OPTIONS}} command returns similar output.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|option|#Errors}} the specified option is unknown.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>db:option('dbpath')</code> returns the database path string.<br />
* <code>db:option('serializer')</code> returns a map with the current serialization parameters.<br />
* <code>declare option db:stripws 'true'; db:option('stripws')</code> returns the locally assigned value.<br />
|}<br />
<br />
==db:info==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:info(<br />
$database as xs:string<br />
) as element(database)</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns meta information on the specified {{Code|$database}}. The output is similar to the {{Command|INFO DB}} command.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br />
|}<br />
<br />
==db:property==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:property(<br />
$database as xs:string,<br />
$name as xs:string<br />
) as xs:anyAtomicType</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the value (string, boolean, integer) of a property with the specified {{Code|$name}} in the specified {{Code|$database}}. The available properties are the ones returned by {{Function||db:info}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|property|#Errors}} the specified property is unknown.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>db:property('db', 'size')</code> returns the number of bytes occupied by the database <code>db</code>.<br />
* <code>db:property('xmark', 'textindex')</code> indicates if the <code>xmark</code> database has a text index.<br />
* <code>db:property('discogs', 'uptodate')</code> indicates if the database statistics and index structures of the <code>discogs</code> database are up-to-date.<br />
|}<br />
<br />
==db:list==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:list(<br />
$database as xs:string := (),<br />
$path as xs:string := ()<br />
) as xs:string*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Without arguments, the names of all databases are returned that are accessible to the current user. If {{Code|$database}} is specified, paths to all resources of this database are returned. The results can be restricted to resources starting with the specified {{Code|$path}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:list("docs")}} returns the names of all documents of a database named {{Code|docs}}.<br />
|}<br />
<br />
==db:list-details==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:list-details(<br />
$database as xs:string := (),<br />
$path as xs:string := ()<br />
) as element()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Without arguments, an element is returned for each database that is accessible to the current user:<br />
* An element has a value, which is the name of the database, and several attributes, which contain the number of stored resources, the modification date, the database size on disk (measured in bytes), and a path to the original database input.<br />
If {{Code|$database}} is specified, an element for each resource in this database is returned:<br />
* An element has a value, which is the name of the resource, and several attributes, which contain the content type, the modification date, the raw flag (which indicates if the resource is binary or XML), and the size of a resource.<br />
* The value of the size attribute depends on the resource type: for documents, it represents the number of nodes; for binary data, it represents the file size (measured in bytes).<br />
* The results can be restricted to resources starting with the specified {{Code|$path}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:list-details("shop")}} returns the names plus additional info on all resources of a database named {{Code|shop}}.<br />
|}<br />
<br />
==db:dir==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:dir(<br />
$database as xs:string,<br />
$path as xs:string<br />
) as element()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns metadata on all directories and resources of a {{Code|$database}} in the specified {{Code|$path}}. Two types of elements are returned:<br />
* {{Code|resource}} represents a resource. The element value is the directory path; content type, modification date, raw flag (which indicates if the resource is binary or XML), and size of the resource are returned as attributes.<br />
* {{Code|dir}} represents a directory. The element value is the directory path; the modification date is returned in an attribute.<br />
The directories are not stored in the internal database layout. Instead, they result implicitly from the paths of stored resources.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br/>{{Error|path|#Errors}} the specified path is invalid.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:dir('shop', 'books')}} returns all entries of the {{Code|books}} directory of a {{Code|shop}} database.<br />
|}<br />
<br />
=Read Operations=<br />
<br />
==db:get==<br />
<br />
{{Announce|Updated with Version 10:}} Renamed (before: {{Code|db:open}}). Due to its widespread use, the old function name will be supported for some more time.<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:get(<br />
$database as xs:string,<br />
$path as xs:string := ()<br />
) as document-node()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns all documents from the specified {{Code|$database}}, or only documents matching the specified {{Code|$path}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:get('docs')}} returns all documents from the database named {{Code|docs}}.<br />
* {{Code|db:get('db', 'one')}} returns all documents from the database named {{Code|db}} located in the path {{Code|one}}.<br />
* <code>for $i in 1 to 3 return db:get('db' || $i)//item</code> returns all item elements from the databases {{Code|db1}}, {{Code|db2}} and {{Code|db3}}.<br />
|}<br />
<br />
==db:get-pre==<br />
<br />
{{Announce|Updated with Version 10:}} Renamed (before: {{Code|db:open-pre}}).<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:get-pre(<br />
$database as xs:string,<br />
$values as xs:integer*<br />
) as node()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns all nodes from a {{Code|$database}} with the specified PRE {{Code|values}} in [[Utility Module#util:ddo|distinct document order]].<br/>The [[Node Storage#PRE Value|PRE value]] provides very fast access to an existing database node, but it will change whenever a node with a smaller ''pre'' values is added to or deleted from a database.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br/>{{Error|range|#Errors}} the specified PRE value does not exist in the database.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:get-pre("docs", 0)}} returns the first database node from the database named {{Code|docs}}.<br />
|}<br />
<br />
==db:get-id==<br />
<br />
{{Announce|Updated with Version 10:}} Renamed (before: {{Code|open-id}}).<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:get-id(<br />
$database as xs:string,<br />
$values as xs:integer*<br />
) as node()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns all nodes from a {{Code|$database}} with the specified ID {{Code|$values}} in [[Utility Module#util:ddo|distinct document order]].<br/>Each database node has a ''persistent'' [[Node Storage#ID Value|ID value]]. Access to the node ID can be sped up by turning on the {{Option|UPDINDEX}} option.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br/>{{Error|range|#Errors}} the specified ID value does not exist in the database.<br />
|}<br />
<br />
==db:get-binary==<br />
<br />
{{Announce|Updated with Version 10}}: renamed (before: {{Code|db:retrieve}}).<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:get-binary(<br />
$database as xs:string,<br />
$path as xs:string<br />
) as item()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns a map with the paths and binary items of all resources in the specified {{Code|$database}}. A single {{Code|xs:base64Binary}} item is returned if a {{Code|$path}} is specified. All items are [[Lazy Module|lazy]], i.e., the actual data will only be retrieved if it is processed.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br/>{{Error|mainmem|#Errors}} the database is not ''persistent'' (stored on disk).<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:get-binary('DB', 'music/01.mp3')}} returns the specified audio file as raw data.<br />
* <code><nowiki>stream:materialize(db:get-binary('DB', 'music/01.mp3'))</nowiki></code> materializes the streamable result in main-memory before returning it.<br />
* <code><nowiki>convert:binary-to-string(db:get-binary('DB', 'info.txt'), 'UTF-8')</nowiki></code> converts a binary database resource as UTF-8 text and returns a string.<br />
|}<br />
<br />
==db:get-value==<br />
<br />
{{Announce|Introduced with Version 10.}}<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:get-value(<br />
$database as xs:string,<br />
$path as xs:string<br />
) as item()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns a map with the paths and values of all resources in the specified {{Code|$database}}. A single value is returned if a {{Code|$path}} is specified.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br/>{{Error|mainmem|#Errors}} the database is not ''persistent'' (stored on disk).<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:get-value('DB', 'sequence')}} returns the specified sequence.<br />
|}<br />
<br />
==db:node-pre==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:node-pre(<br />
$nodes as node()*<br />
) as xs:integer*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the PRE values of the specified {{Code|$nodes}}, which must all be [[#Database Nodes|database nodes]].<br/>The [[Node Storage#PRE Value|PRE value]] provides very fast access to an existing database node, but it will change whenever a node with a smaller ''pre'' values is added to or deleted from a database.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|node|#Errors}} {{Code|$nodes}} contains a node which is not stored in a database.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:node-pre(doc("input"))}} returns {{Code|0}} if the database {{Code|input}} contains a single document.<br />
|}<br />
<br />
==db:node-id==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:node-id(<br />
$nodes as node()*<br />
) as xs:integer*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the ID values of the specified {{Code|$nodes}}, which must all be [[#Database Nodes|database nodes]].<br/>Each database node has a ''persistent'' [[Node Storage#ID Value|ID value]]. Access to the node id can be sped up by turning on the {{Option|UPDINDEX}} option.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|node|#Errors}} {{Code|$nodes}} contains a node which is not stored in a database.<br />
|}<br />
<br />
==db:export==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:export(<br />
$database as xs:string,<br />
$path as xs:string,<br />
$options as map(*)? := map { }<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Exports the specified {{Code|$database}} to the specified file {{Code|$path}}. Existing files will be overwritten.<br/>The {{Code|$options}} argument contains [[Serialization|serialization parameters]] (see [https://www.w3.org/TR/xpath-functions-31/#func-serialize fn:serialize()]).<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br />
|- valign="top"<br />
| '''Examples'''<br />
| Export all files as text:<br/><br />
<syntaxhighlight lang="xquery"><br />
db:export("DB", "/home/john/xml/texts", map { 'method': 'text' })<br />
</syntaxhighlight><br />
The following code can be used to export parts of the database:<br />
<syntaxhighlight lang="xquery"><br />
let $target := '/home/john/xml/target'<br />
for $doc in db:get('DB', 'collection')<br />
let $path := $target || db:path($doc)<br />
return (<br />
file:create-dir(file:parent($path)),<br />
file:write($path, $doc)<br />
)<br />
</syntaxhighlight><br />
|}<br />
<br />
=Value Indexes=<br />
<br />
==db:text==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:text(<br />
$database as xs:string,<br />
$values as xs:string*<br />
) as text()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns all text nodes of a {{Code|$database}} that match one of the specified {{Code|$values}} and that are stored in the text index.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br/>{{Error|no-index|#Errors}} the index is not available.<br/><br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:text("DB", "QUERY")/..}} returns the parents of all text nodes of the database {{Code|DB}} that match the string {{Code|QUERY}}.<br />
|}<br />
<br />
==db:text-range==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:text-range(<br />
$database as xs:string,<br />
$min as xs:string,<br />
$max as xs:string<br />
) as text()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns all text nodes of a {{Code|$database}} whose values are larger than or equal to {{Code|$min}} and smaller than or equal to {{Code|$max}} and that are stored in the text index.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br/>{{Error|no-index|#Errors}} the index is not available.<br/><br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:text-range("DB", "2000", "2001")}} returns all text nodes of the database {{Code|DB}} that are found in between {{Code|2000}} and {{Code|2001}}.<br />
|}<br />
<br />
==db:attribute==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:attribute(<br />
$database as xs:string,<br />
$values as xs:string*,<br />
$name as xs:string := ()<br />
) as attribute()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns all attribute nodes of a {{Code|$database}} that match one of the specified {{Code|$values}} and that are stored in the attribute index.<br/>If {{Code|$name}} is specified, the resulting attribute nodes are filtered by their attribute name.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br/>{{Error|no-index|#Errors}} the index is not available.<br/><br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:attribute("DB", "QUERY", "id")/..}} returns the parents of all {{Code|id}} attribute nodes of the database {{Code|DB}} that have {{Code|QUERY}} as string value.<br />
|}<br />
<br />
==db:attribute-range==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:attribute-range(<br />
$database as xs:string,<br />
$min as xs:string,<br />
$max as xs:string,<br />
$name as xs:string := ()<br />
) as attribute()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns all attributes of a {{Code|$database}} whose values are larger than or equal to {{Code|$min}} and smaller than or equal to {{Code|$max}} and that are stored in the attribute index.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br/>{{Error|no-index|#Errors}} the index is not available.<br/><br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:attribute-range("DB", "id456", "id473", 'id')}} returns all {{Code|@id}} attributes of the database {{Code|DB}} that have a string value in between {{Code|id456}} and {{Code|id473}}.<br />
|}<br />
<br />
==db:token==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:token(<br />
$database as xs:string,<br />
$tokens as xs:string*,<br />
$name as xs:string := ()<br />
) as attribute()*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns all attribute nodes of a {{Code|$database}} the values of which contain one of the specified {{Code|$tokens}}.<br/>If {{Code|$name}} is specified, the resulting attribute nodes are filtered by their attribute name.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br/>{{Error|no-index|#Errors}} the index is not available.<br/><br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:token("DB", "row", "class")/parent::div}} returns all {{Code|div}} nodes of database {{Code|DB}} with a {{Code|class}} attribute that contains the token {{Code|row}}.<br />
|}<br />
<br />
=Updates=<br />
<br />
All functions in this section are [[#Updating Functions|Updating Functions]].<br />
<br />
==db:create==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:create(<br />
$database as xs:string,<br />
$inputs as item()* := (),<br />
$paths as xs:string* := (),<br />
$options as map(*)? := map { }<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Creates a new {{Code|$database}} and adds the supplied {{Code|$inputs}} to the specified {{Code|$paths}}:<br />
* The inputs may be strings or nodes:<br />
** nodes may be of any type except for attributes<br />
** strings can be a URI pointing to a file/directory or an XML string (which is detected by the leading <code>&lt;</code> character)<br />
** a path must be specified if the input is not a file or directory reference<br />
* The parsing and indexing behavior can be controlled via {{Code|$options}}:<br />
** allowed options are {{Option|ADDCACHE}} and the [[Options#Indexing|indexing]], [[Options#Full-Text Indexing|full-text indexing]], [[Options#Parsing|parsing]] and [[Options#XML Parsing|XML parsing]] options, all in lower case<br />
** parsing options will only impact string input (URIs, XML strings) because nodes have already been parsed.<br />
* An existing database will be overwritten.<br />
* Database creation takes place after most other update operations (see [[XQuery Update#Pending Update List|Pending Update List]]). As a consequence, a newly created database cannot be addressed in the same query.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|lock|#Errors}} a database is opened by another process.<br/>{{Error|name|#Errors}} the specified name is not a [[Commands#Valid_Names|valid database name]].<br/>{{Error|conflict|#Errors}} the same database was addressed more than once.<br/>{{Error|args|#Errors}} the number of specified inputs and paths differs.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:create("DB")}} creates the empty database {{Code|DB}}.<br />
* {{Code|db:create("DB", "/home/dir/doc.xml")}} creates the database {{Code|DB}} and adds the document {{Code|/home/dir/doc.xml}} as initial content.<br />
* {{Code|db:create("DB", <a/>, "doc.xml")}} creates the database {{Code|DB}} and adds the document with content {{Code|&lt;a/&gt;}} under the name {{Code|doc.xml}}.<br />
* {{Code|db:create("DB", "/home/dir/", "docs/dir")}} creates the database {{Code|DB}} and adds the documents in {{Code|/home/dir}} to the database under the path {{Code|docs/dir}}.<br />
* <code>db:create("DB", file:list('.'), (), map { 'ftindex': true() })</code> adds all files of the current working directory to a new database, preserving relative filesystem paths and creating a full-text index.<br />
|}<br />
<br />
==db:add==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:add(<br />
$database as xs:string,<br />
$input as item(),<br />
$path as xs:string? := (),<br />
$options as map(*)? := map { }<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Adds the specified {{Code|$input}} to a {{Code|$database}} with the specified {{Code|$path}}:<br />
* A document with the same path may occur more than once in a database. If you want to enforce single instances, use {{Function||db:put}} instead.<br />
* See {{Function||db:create}} for more details on the input and path arguments.<br />
* The parsing behavior can be controlled via {{Code|$options}}:<br />
** allowed options are {{Option|ADDCACHE}} and the [[Options#Parsing|parsing]] and [[Options#XML Parsing|XML parsing]] options, all in lower case<br />
** parsing options will only impact string input (URIs, XML strings) because nodes have already been parsed<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* <code>db:add("DB", "/home/dir/doc.xml")</code> adds the file {{Code|/home/dir/doc.xml}} to the database {{Code|DB}}.<br />
* <code>db:add("DB", <a/>, "doc.xml")</code> adds a document node to the database {{Code|DB}} under the name {{Code|doc.xml}}.<br />
* <code>db:add("DB", "/home/dir", "docs/dir", map { 'addcache': true() })</code> adds all documents in {{Code|/home/dir}} to the database {{Code|DB}} under the path {{Code|docs/dir}}. To reduce memory consumption, the files will be cached before being added to the database.<br />
|}<br />
<br />
==db:put==<br />
<br />
{{Announce|Updated with Version 10}}: renamed (before: {{Code|db:replace}}); function signature aligned with {{Function||db:add}} (second and third argument swapped).<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:put(<br />
$database as xs:string,<br />
$input as item(),<br />
$path as xs:string,<br />
$options as map(*)? := map { }<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Replaces a resource, specified by {{Code|$path}}, in a {{Code|$database}} with the contents of {{Code|$input}}, or adds it as a new resource:<br />
* The parsing behavior can be controlled via {{Code|$options}}:<br />
** Allowed options are {{Option|ADDCACHE}} and the [[Options#Parsing|parsing]] and [[Options#XML Parsing|XML parsing]] options, all in lower case.<br />
** Parsing options will only impact string input (URIs, XML strings), because nodes have already been parsed.<br />
* See {{Function||db:create}} for more details on the input argument.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br/>{{Error|target|#Errors}} the path points to a directory.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:put("DB", "/home/dir/doc.xml", "docs/dir/doc.xml")}} replaces the content of the document {{Code|docs/dir/doc.xml}} in the database {{Code|DB}} with the content of the file {{Code|/home/dir/doc.xml}}.<br />
* {{Code|db:put("DB", "<a/>", "docs/dir/doc.xml")}} replaces the content of the document {{Code|docs/dir/doc.xml}} in the database {{Code|DB}} with {{Code|&lt;a/&gt;}}.<br />
* {{Code|db:put("DB", document { <a/> }, "docs/dir/doc.xml")}} replaces the content of the document {{Code|docs/dir/doc.xml}} in the database {{Code|DB}} with the specified document node.<br />
The following query can be used to import files from a directory to a database:<br />
<syntaxhighlight lang="xquery"><br />
let $source := '/home/john/xml/source'<br />
for $file in file:list($source, true())<br />
let $path := $source || $file<br />
where not(file:is-dir($path))<br />
return db:put('db', doc($path), $file)<br />
</syntaxhighlight><br />
|}<br />
<br />
==db:put-binary==<br />
<br />
{{Announce|Updated with Version 10}}: renamed (before: {{Code|db:put}}); function signature aligned with {{Function||db:add}} (second and third argument swapped).<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:put-binary(<br />
$database as xs:string,<br />
$input as item(),<br />
$path as xs:string<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Stores a binary resource specified by {{Code|$input}} in a {{Code|$database}} at the specified {{Code|$path}}. Existing resources are overwritten.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br/>{{Error|mainmem|#Errors}} the database is not ''persistent'' (stored on disk).<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:put-binary('DB', file:read-binary('video.mov'), 'video/sample.mov')}} stores the addressed video file at the specified location.<br />
* With the following query, you can copy the binary resources of one database into another:<br />
<syntaxhighlight lang="xquery"><br />
let $db := 'db'<br />
let $src-path := 'src/'<br />
let $trg-path := 'trg/'<br />
for $src in db:list($db, $src-path)<br />
where db:type($db, $src) = 'binary'<br />
let $trg := $trg-path || substring-after($src, $src-path)<br />
return db:put-binary($db, db:get-binary($db, $src), $trg)<br />
</syntaxhighlight><br />
|}<br />
<br />
==db:put-value==<br />
<br />
{{Announce|Introduced with Version 10.}}<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:put-value(<br />
$database as xs:string,<br />
$input as item()*,<br />
$path as xs:string<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Stores an {{Code|$input}} value in a {{Code|$database}} at the specified {{Code|$path}}. Existing resources are overwritten. The value can be an arbitrary sequence of atomic items, nodes, maps, and arrays.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br/>{{Error|mainmem|#Errors}} the database is not ''persistent'' (stored on disk).<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:put-value('DB', 1 to 10000, 'sequence')}} stores a numeric range in the database.<br />
* With the following query, a map with countries and associated cities is stored in a database. The value resource can e.g. be used as index in future queries:<br />
<syntaxhighlight lang="xquery"><br />
db:put-value(<br />
'factbook',<br />
map:merge(<br />
for $country in db:get('factbook')//country<br />
return map:entry($country/@name, $country//city/name ! string())<br />
),<br />
'cities'<br />
)</syntaxhighlight><br />
|}<br />
<br />
==db:delete==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:delete(<br />
$database as xs:string,<br />
$path as xs:string<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Deletes resource(s), specified by {{Code|$path}}, from the specified {{Code|$database}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br/>{{Error|path|#Errors}} the specified path is invalid.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:delete("DB", "docs/dir/doc.xml")}} deletes the resource {{Code|docs/dir/doc.xml}} from {{Code|DB}}.<br />
* {{Code|db:delete("DB", "docs/dir")}} deletes all resources from {{Code|DB}} in the specified path {{Code|docs/dir}}.<br />
|}<br />
<br />
==db:copy==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:copy(<br />
$database as xs:string,<br />
$new-name as xs:string<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Creates a copy of {{Code|$database}}, which will be called {{Code|$new-name}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br/>{{Error|lock|#Errors}} a database is opened by another process.<br/>{{Error|name|#Errors}} invalid database name.<br/>{{Error|conflict|#Errors}} the same database was addressed more than once.<br />
|}<br />
<br />
==db:alter==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:alter(<br />
$database as xs:string,<br />
$new-name as xs:string<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Renames a {{Code|$database}} to {{Code|$new-name}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br/>{{Error|lock|#Errors}} a database is opened by another process.<br/>{{Error|name|#Errors}} invalid database name.<br/>{{Error|conflict|#Errors}} the same database was addressed more than once.<br />
|}<br />
<br />
==db:optimize==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:optimize(<br />
$database as xs:string,<br />
$all as xs:boolean? := false(),<br />
$options as map(*)? := map { }<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Optimizes the metadata and indexes of a {{Code|$database}}.<br/>If {{Code|$all}} is {{Code|true}}, the complete database will be rebuilt.<br/>The {{Code|$options}} argument can be used to control indexing. The syntax is identical to the {{Function||db:create}} function: Allowed options are all [[Options#Indexing|indexing]] and [[Options#Full-Text|full-text]] options. {{Option|UPDINDEX}} is only supported if {{Code|$all}} is {{Code|true}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:optimize("DB")}} optimizes the database structures of the database {{Code|DB}}.<br />
* <code>db:optimize("DB", true(), map { 'ftindex': true() })</code> optimizes all database structures of the database {{Code|DB}} and creates a full-text index.<br />
|}<br />
<br />
==db:rename==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:rename(<br />
$database as xs:string,<br />
$source as xs:string,<br />
$target as xs:string<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Moves all resources(s) of a {{Code|$database}}, which are found in the supplied {{Code|$source}} path, to the supplied {{Code|$target}} path. The paths may point to single resources or directories. No updates will take place if a non-existing source path is supplied.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br/>{{Error|path|#Errors}} the specified source or target path, or one of its descendants, is invalid.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:rename("DB", "docs/dir/doc.xml", "docs/dir/newdoc.xml")}} renames the resource {{Code|docs/dir/doc.xml}} to {{Code|docs/dir/newdoc.xml}} in the database {{Code|DB}}.<br />
* {{Code|db:rename("DB", "docs/dir", "docs/newdir")}} moves all resources in the database {{Code|DB}} from {{Code|docs/dir}} to {Code|docs/newdir}}.<br />
|}<br />
<br />
==db:flush==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:flush(<br />
$database as xs:string<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Explicitly flushes the buffers of a {{Code|$database}}. This command is only useful if {{Option|AUTOFLUSH}} has been set to {{Code|false}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br />
|}<br />
<br />
==db:drop==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:drop(<br />
$database as xs:string<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Drops a {{Code|$database}} and all connected resources.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br/>{{Error|lock|#Errors}} a database is opened by another process.<br/>{{Error|conflict|#Errors}} the same database was addressed more than once.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:drop("DB")}} drops the database {{Code|DB}}.<br />
|}<br />
<br />
=Backups=<br />
<br />
{{Announce|Introduced with Version 10:}} Support for general data ([[User Management|registered users]], [[Job Module#Services|scheduled services]] and [[Store Module|key-value stores]]).<br />
<br />
All functions in this section except for {{Function||db:backups}} are {{Function|Database|Updating Functions}}.<br />
<br />
==db:create-backup==<br />
<br />
{{Announce|Updated with Version 10:}} Options argument added.<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:create-backup(<br />
$database as xs:string,<br />
$options as map(*)? := map { }<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Creates a backup of a {{Code|$database}}. If no name is supplied, general data will be backed up. The following {{Code|$options}} are available:<br />
* With {{Code|comment}}, a comment string can be attached to the backup.<br />
* By setting {{Code|compress}} to false, the backup will be created faster, but it will take more space on disk.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br/>{{Error|name|#Errors}} invalid database name.<br/>{{Error|conflict|#Errors}} the same database was addressed more than once.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:create-backup('DB', map { 'compress': false() })}} creates a backup of the database {{Code|DB}} without compressing its entries.<br />
|}<br />
<br />
==db:drop-backup==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:drop-backup(<br />
$name as xs:string<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Drops all backups of the database with the specified {{Code|$name}}. If the name ends with a timestamp, only the specified backup file will be deleted. If no name is supplied, backups with general data are addressed.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|backup|#Errors}} No backup file found.<br/>{{Error|name|#Errors}} invalid database name.<br/>{{Error|conflict|#Errors}} the same database was addressed more than once.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:drop-backup("DB")}} drops all backups of the database {{Code|DB}}.<br />
* {{Code|db:drop-backup("DB-2014-03-13-17-36-44")}} drops the specific backup file {{Code|DB-2014-03-13-17-36-44.zip}} of the database {{Code|DB}}.<br />
|}<br />
<br />
==db:alter-backup==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:alter-backup(<br />
$name as xs:string,<br />
$new-name as xs:string<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Renames all backups of the database with the specified {{Code|$name}} to {{Code|$new-name}}. If the name ends with a date, only the specified backup file will be renamed.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|backup|#Errors}} No backup file found.<br/>{{Error|name|#Errors}} invalid database name.<br/>{{Error|conflict|#Errors}} the same database was addressed more than once.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:alter-backup("DB", "DB2)}} renames all backups of the database {{Code|DB}} to {{Code|DB2}}.<br />
|}<br />
<br />
==db:restore==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:restore(<br />
$name as xs:string<br />
) as empty-sequence()</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Restores the database with the specified {{Code|$name}}. The {{Code|$name}} may include the timestamp of the backup file. If no name is supplied, general data will be restored. If general data is restored, it will only be available after BaseX has been restarted.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|lock|#Errors}} a database is opened by another process.<br/>{{Error|name|#Errors}} invalid database name.<br/>{{Error|no-backup|#Errors}} No backup found.<br/>{{Error|conflict|#Errors}} the same database was addressed more than once.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:restore("DB")}} restores the database {{Code|DB}}.<br />
* {{Code|db:restore("DB-2014-03-13-18-05-45")}} restores the database {{Code|DB}} from the backup file with the given timestamp.<br />
|}<br />
<br />
==db:backups==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:backups(<br />
$database as xs:string := ()<br />
) as element(backup)*</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns an element sequence containing all available database backups with timestamp, file size and comment.<br/>If a {{Code|$database}} is specified, the sequence will be restricted to the backups matching this database.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:backups("factbook")}} returns all backups that have been made from the {{Code|factbook}} database.<br />
|}<br />
<br />
=Helper Functions=<br />
<br />
==db:name==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:name(<br />
$node as node()<br />
) as xs:string</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the name of the database in which the specified [[#Database Nodes|database node]] {{Code|$node}} is stored.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|node|#Errors}} {{Code|$nodes}} contains a node which is not stored in a database.<br />
|}<br />
<br />
==db:path==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:path(<br />
$node as node()<br />
) as xs:string</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the path of the database document in which the specified [[#Database Nodes|database node]] {{Code|$node}} is stored.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|node|#Errors}} {{Code|$nodes}} contains a node which is not stored in a database.<br />
|}<br />
<br />
==db:exists==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:exists(<br />
$database as xs:string,<br />
$path as xs:string := ()<br />
) as xs:boolean</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Checks if a {{Code|$database}} exists, or a resource located at {{Code|$path}} in this database.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:exists("DB")}} returns {{Code|true}} if the database {{Code|DB}} exists.<br />
* {{Code|db:exists("DB", "resource")}} returns {{Code|true}} if {{Code|resource}} exists in this database.<br />
|}<br />
<br />
==db:type==<br />
<br />
{{Announce|Introduced with BaseX 10:}} Replaces {{Code|db:is-raw}} and {{Code|db:is-xml}}.<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:type(<br />
$database as xs:string,<br />
$path as xs:string<br />
) as xs:boolean</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Returns the type ({{Code|xml}}, {{Code|binary}}, {{Code|value}}) of a resource in a {{Code|$database}} at the specified {{Code|$path}}.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:type("DB", "factbook.xml")}} returns {{Code|true}} if the specified resource is an XML document.<br />
|}<br />
<br />
==db:content-type==<br />
<br />
{| width='100%'<br />
|- valign="top"<br />
| width='120' | '''Signature'''<br />
|<pre>db:content-type(<br />
$database as xs:string,<br />
$path as xs:string<br />
) as xs:string</pre><br />
|- valign="top"<br />
| '''Summary'''<br />
|Retrieves the content-type of a resource in a {{Code|$database}} at the specified {{Code|$path}}.<br/>The file extension is used to recognize the content-type of a resource stored in the database. {{Code|application/xml}} will be returned for any XML document stored in the database, regardless of its file name extension.<br />
|- valign="top"<br />
| '''Errors'''<br />
|{{Error|open|#Errors}} the addressed database does not exist or could not be opened.<br />
|- valign="top"<br />
| '''Examples'''<br />
|<br />
* {{Code|db:content-type("DB", "docs/doc01.pdf")}} returns {{Code|application/pdf}}.<br />
* {{Code|db:content-type("DB", "docs/doc01.xml")}} returns {{Code|application/xml}}.<br />
* {{Code|db:content-type("DB", "docs/doc01")}} returns {{Code|application/xml}}, if {{Code|db:is-xml("DB", "docs/doc01")}} returns {{Code|true}}.<br />
|}<br />
<br />
=Errors=<br />
<br />
{| class="wikitable" width="100%"<br />
! width="110"|Code<br />
|Description<br />
|- valign="top"<br />
|{{Code|args}}<br />
|The number of specified inputs and paths differs.<br />
|- valign="top"<br />
|{{Code|conflict}}<br />
|Multiple update operations point to the same target.<br />
|- valign="top"<br />
|{{Code|lock}}<br />
|A database cannot be updated because it is opened by another process.<br />
|- valign="top"<br />
|{{Code|mainmem}}<br />
|The addressed database is not ''persistent'' (stored on disk).<br />
|- valign="top"<br />
|{{Code|name}}<br />
|The name of the specified database is invalid.<br />
|- valign="top"<br />
|{{Code|no-backup}}<br />
|No backup exists for a database.<br />
|- valign="top"<br />
|{{Code|node}}<br />
|The referenced XML node is no [[#Database Nodes|database node]], i.e. it is neither stored in a database nor represented as database fragment.<br />
|- valign="top"<br />
|{{Code|no-index}}<br />
|The database lacks an index structure required by the called function.<br />
|- valign="top"<br />
|{{Code|open}}<br />
|The addressed database does not exist or could not be opened.<br />
|- valign="top"<br />
|{{Code|option}}<br />
|The specified option is unknown.<br />
|- valign="top"<br />
|{{Code|path}}<br />
|The specified database path is invalid.<br />
|- valign="top"<br />
|{{Code|property}}<br />
|The specified database property is unknown.<br />
|- valign="top"<br />
|{{Code|range}}<br />
|The addressed database ID or PRE value is out of range.<br />
|- valign="top"<br />
|{{Code|target}}<br />
|Path points to an invalid target.<br />
|}<br />
<br />
=Changelog=<br />
<br />
;Version 10<br />
* Added: {{Function||db:get}}, {{Function||db:put}}, {{Function||db:type}}.<br />
* Added: [[#Backups|Backups]]: Support for general data ([[User Management|registered users]], [[Job Module#Services|scheduled services]] and [[Store Module|key-value stores]]).<br />
* Updated: {{Function||db:get}}, {{Function||db:get-id}}, {{Function||db:get-pre}} renamed (before: {{Code|db:open}}, {{Code|db:open-id}}, {{Code|db:open-pre}})<br />
* Updated: {{Function||db:put}} renamed (before: {{Code|db:replace}}); function signature aligned with {{Function||db:add}} (second and third argument swapped).<br />
* Updated: {{Function||db:put-binary}} renamed (before: {{Code|db:store}}); function signature aligned with {{Function||db:add}} (second and third argument swapped).<br />
* Updated: {{Function||db:get-binary}} renamed (before: {{Code|db:retrieve}}).<br />
* Updated: {{Function||db:backups}}, {{Function||db:create-backup}}: Options added.<br />
* Removed: {{Code|db:is-raw}}, {{Code|db:is-raw}} (new: {{Function||db:type}}).<br />
<br />
;Version 9.3<br />
* Added: {{Function||db:alter-backup}}<br />
* Updated: {{Code|db:open-id}}, {{Code|db:open-pre}}: support for multiple integers<br />
<br />
;Version 9.2<br />
* Added: {{Function||db:dir}}<br />
* Updated: {{Function||db:add}}: {{Code|$path}} allow empty path argument<br />
<br />
;Version 9.0<br />
* Added: {{Function||db:option}}<br />
* Updated: db:output renamed to {{Function|Update|update:output}}, db:output-cache renamed to {{Function|Update|update:cache}}<br />
* Updated: error codes updated; errors now use the module namespace<br />
<br />
;Version 8.6<br />
* Added: {{Function||db:property}}<br />
<br />
;Version 8.4<br />
* Updated: {{Function||db:create}}, {{Function||db:add}}, {{Code|db:replace}}: support for {{Code|ADDCACHE}} option.<br />
* Added: {{Function||db:token}}<br />
<br />
;Version 8.3<br />
* Updated: {{Function||db:list-details}}: attributes with name of database and date of backup added to results.<br />
* Updated: {{Function||db:backups}} now include attributes with name of database and date of backup.<br />
* Updated: {{Function|Database|Value Indexes}}: raise error if no index exists.<br />
<br />
;Version 8.2<br />
* Added: {{Function||db:output-cache}}<br />
* Removed: db:event<br />
<br />
;Version 7.9<br />
* Updated: parsing options added to {{Function||db:create}}, {{Function||db:add}} and {{Code|db:replace}}.<br />
* Updated: allow {{Option|UPDINDEX}} if {{Code|$all}} is {{Code|true}}.<br />
<br />
;Version 7.8.2<br />
* Added: {{Function||db:alter}}, {{Function||db:copy}}, {{Function||db:create-backup}}, {{Function||db:drop-backup}}, {{Function||db:restore}}<br />
<br />
;Version 7.8<br />
* Removed: db:fulltext (use {{Function|Full-Text|ft:search}} instead)<br />
<br />
;Version 7.7<br />
* Added: {{Function||db:export}}, {{Function||db:name}}, {{Function||db:path}}<br />
* Updated: {{Code|$options}} argument added to {{Function||db:create}} and {{Function||db:optimize}}.<br />
* Updated: the functions no longer accept [[#Database Nodes|database nodes]] as reference. Instead, the name of a database must now be specified.<br />
<br />
;Version 7.6<br />
* Updated: {{Function||db:create}}: allow more than one input and path.<br />
<br />
;Version 7.5<br />
* Updated: {{Function||db:add}}: input nodes will be automatically converted to document nodes<br />
* Added: {{Function||db:backups}}<br />
* Added: {{Function||db:create}}<br />
* Added: {{Function||db:drop}}<br />
<br />
;Version 7.3<br />
* Added: {{Function||db:flush}}<br />
<br />
;Version 7.2.1<br />
* Added: {{Function||db:text-range}}, {{Function||db:attribute-range}}, {{Function||db:output}}<br />
<br />
;Version 7.1<br />
* Added: {{Function||db:list-details}}, {{Function||db:content-type}}<br />
* Updated: {{Function||db:info}}, {{Function||db:system}}, {{Code|db:retrieve}}<br />
<br />
;Version 7.0<br />
* Added: {{Function||db:exists}}, {{Code|db:retrieve}}, {{Code|db:store}}, {{Code|db:is-raw}}, {{Code|db:is-xml}}<br />
* Updated: {{Function||db:list}}, {{Code|db:open}}, {{Function||db:add}}</div>Andy Buncehttps://docs.basex.org/index.php?title=Java_Bindings&diff=16198Java Bindings2022-07-27T09:25:53Z<p>Andy Bunce: is->if</p>
<hr />
<div>This article is part of the [[XQuery|XQuery Portal]]. It demonstrates different ways to invoke Java code from XQuery, and it presents extensions to access the current query context from Java.<br />
<br />
The Java Binding feature is an extensibility mechanism which enables developers<br />
to directly access Java variables and execute code from XQuery. Addressed Java code must either be contained in the Java classpath, or it must be located in the [[Repository]].<br />
<br />
Please bear in mind that the execution of Java code may cause side effects that conflict with the functional nature of XQuery, or may introduce new security risks to your project.<br />
<br />
Some more notes:<br />
* With the middle dot notation, three adjacent dots can be used to specify array types.<br />
* The path to the standard package {{Code|java.lang.}} can be omitted.<br />
* Java objects are wrapped into function items.<br />
* Results of constructor calls are always returned as function item.<br />
* With {{Option|WRAPJAVA}}, it can be controlled how Java values are converted to XQuery.<br />
<br />
=Identification=<br />
<br />
==Classes==<br />
<br />
A Java class is identified by a namespace URI. The original URI is rewritten as follows:<br />
<br />
# The [[#URI Rewriting|URI Rewriting]] steps are applied to the URI.<br />
# Slashes in the resulting URI are replaced with dots.<br />
# The last path segment of the URI is capitalized and rewritten to [https://en.wikipedia.org/wiki/CamelCase CamelCase].<br />
<br />
The normalization steps are skipped if the URI is prefixed with {{Code|java:}}. The path to the standard package {{Code|java.lang.}} can be omitted:<br />
<br />
* <code><nowiki>http://basex.org/modules/meta-data</nowiki></code> → <code>org.basex.modules.MetaData</code><br />
* <code>java:java.lang.String</code> → <code>java.lang.String</code><br />
* <code>StringBuilder</code> → <code>java.lang.StringBuilder</code><br />
<br />
==Functions and Variables==<br />
<br />
Java constructors, functions and variables can be referenced and evaluated by the existing XQuery function syntax:<br />
<br />
* The namespace of the function name identifies the Java class.<br />
* The local part of the name, which is rewritten to camel case, identifies a variable or function of that class.<br />
* The middle dot character <code>[https://www.fileformat.info/info/unicode/char/b7/index.htm ·]</code> (<code>&amp;#xB7;</code>, a valid character in XQuery names, but not in Java) can be used to append exact Java parameter types to the function name. Class types must be referenced by their full path. Three adjacent dots can be used to address an array argument.<br />
<br />
{| class="wikitable"<br />
|- valign="top"<br />
! Addressed code<br />
! XQuery<br />
! Java<br />
|- valign="top"<br />
| Variable<br />
| <code>Q{Integer}MIN_VALUE()</code><br />
| <code>Integer.MIN_VALUE</code><br />
|- valign="top"<br />
| Function<br />
| <code>Q{Object}hash-code($object)</code><br />
| <code>object.hashCode()</code><br />
|- valign="top"<br />
| Function with argument<br />
| <code>Q{String}split·String·int($string, ';', xs:int(3))</code><br />
| <code>string.split(";", 3)</code><br />
|- valign="top"<br />
| Constructor with array argument<br />
| <code>Q{String}new·byte...(xs:hexBinary('414243'))</code><br />
| <code>new String(new byte[] { 41, 42, 43 })</code><br />
|}<br />
<br />
As XQuery and Java have different type systems, XQuery arguments must be converted to equivalent Java values, and the result of a Java function is converted back to an XQuery value (see [[#Data Types|Data Types]]).<br />
<br />
If the Java function you want to address is not detected, you may need to cast your values to the target type. For example, if a Java function expects a primitive {{Code|int}} value, you will need to convert your XQuery integers to {{Code|xs:int}}.<br />
<br />
=Namespace Declarations=<br />
<br />
In the following example, the Java {{Code|Math}} class is referenced. When executed, the query returns the cosine of an angle by calling the static method {{Code|cos()}}, and the value of π by addressing the static variable via {{Code|PI()}}:<br />
<br />
<syntaxhighlight lang="xquery"><br />
declare namespace math = "java:java.lang.Math";<br />
math:cos(xs:double(0)), math:PI()<br />
</syntaxhighlight><br />
<br />
With the [[XQuery 3.0#Expanded QNames|Expanded QName]] notation of XQuery 3.0, the namespace can directly be embedded in the function call:<br />
<br />
<syntaxhighlight lang="xquery"><br />
Q{java:java.lang.Math}cos(xs:double(0))<br />
</syntaxhighlight><br />
<br />
The constructor of a class can be invoked by calling the virtual function {{Code|new()}}. Instance methods can then called by passing on the resulting Java object as first argument. In the following example, 256 bytes are written to the file {{Code|output.txt}}. First, a new {{Code|FileWriter}} instance is created, and its {{Code|write()}} function is called in the next step:<br />
<br />
<syntaxhighlight lang="xquery"><br />
declare namespace fw = 'java:java.io.FileWriter';<br />
let $file := fw:new('output.txt')<br />
return (<br />
for $i in 0 to 255<br />
return fw:write($file, xs:int($i)),<br />
fw:close($file)<br />
)<br />
</syntaxhighlight><br />
<br />
If the result of a Java call contains invalid XML characters, it will be rejected. The validity check can be disabled by setting {{Option|CHECKSTRINGS}} to false. In the example below, a file with a single {{Code|00}} byte is written, and this file will then be accessed by via Java functions:<br />
<br />
<syntaxhighlight lang="xquery"><br />
declare namespace br = 'java:java.io.BufferedReader';<br />
declare namespace fr = 'java:java.io.FileReader';<br />
<br />
declare option db:checkstrings 'false';<br />
<br />
(: write file :)<br />
file:write-binary('00.bin', xs:hexBinary('00')),<br />
(: read file :)<br />
let $br := br:new(fr:new('00.bin'))<br />
return (<br />
br:readLine($br), <br />
br:close($br)<br />
)<br />
</syntaxhighlight><br />
<br />
The option can also be specified via a pragma:<br />
<br />
<syntaxhighlight lang="xquery"><br />
(# db:checkstrings #) {<br />
br:new(fr:new('00.bin')) ! (br:readLine(.), br:close(.))<br />
}<br />
</syntaxhighlight><br />
<br />
=Module Imports=<br />
<br />
A Java class can be instantiated by ''importing'' them as a module: A new instance of the addressed class will be constructed, which can then be referenced in the query body.<br />
<br />
In the (side-effecting) example below, a HashSet instance is created, values are added, and the size of the set is returned. As {{Code|set:add()}} returns boolean values, {{Function|Profiling|prof:void}} is used to swallow the values:<br />
<br />
<syntaxhighlight lang="xquery"><br />
import module namespace set = "java:java.util.HashSet";<br />
prof:void(<br />
for $s in ("one", "two", "one")<br />
return set:add($s)<br />
),<br />
set:size()<br />
</syntaxhighlight><br />
<br />
The execution of imported classes is more efficient than the execution of instances that have been created via {{Code|new()}}. In turn, no arguments can be supplied in the import statement, and the construction will only be successful if the class can be instantiated without arguments.<br />
<br />
=Integration=<br />
<br />
Java classes can be coupled more closely to BaseX. If a class inherits the abstract [https://github.com/BaseXdb/basex/blob/master/basex-core/src/main/java/org/basex/query/QueryModule.java QueryModule] class, the two variables [https://github.com/BaseXdb/basex/blob/master/basex-core/src/main/java/org/basex/query/QueryContext.java queryContext] and [https://github.com/BaseXdb/basex/blob/master/basex-core/src/main/java/org/basex/query/StaticContext.java staticContext] get available, which provide access to the global and static context of a query.<br />
<br />
The [https://github.com/BaseXdb/basex/blob/master/basex-core/src/main/java/org/basex/query/QueryResource.java QueryResource] interface can be implemented to enforce finalizing operations, such as the closing of opened connections or resources in a module. Its {{Code|close()}} method will be called after the XQuery expression has been fully evaluated.<br />
<br />
==Annotations==<br />
<br />
The internal properties of functions can be assigned via annotations:<br />
<br />
* Java functions can only be executed by users with [[User_Management|Admin permissions]]. You can annotate a function with {{Code|@Requires(<Permission>)}} to also make it accessible to users with fewer privileges.<br />
* Java code is treated as ''non-deterministic'', as its behavior cannot be predicted by the XQuery processor. You may annotate a function as {{Code|@Deterministic}} if you know that it will have no side effects and will always yield the same result.<br />
* Java code is treated as ''context-independent''. If a function accesses the query context, it should be annotated as {{Code|@ContextDependent}}<br />
* Java code is treated as ''focus-independent''. If a function accesses the current context item, position or size, it should be annotated as {{Code|@FocusDependent}}<br />
<br />
In the following code, information from the static query context is returned by the first function, and a query exception is raised by the second function:<br />
<br />
<syntaxhighlight lang="xquery"><br />
import module namespace context = 'org.basex.examples.query.ContextModule';<br />
<br />
element user {<br />
context:user()<br />
},<br />
try {<br />
element to-int { context:to-int('abc') }<br />
} catch basex:error {<br />
element error { $err:description }<br />
}<br />
</syntaxhighlight><br />
<br />
The imported Java class is shown below:<br />
<br />
<syntaxhighlight lang="java"><br />
package org.basex.examples.query;<br />
<br />
import org.basex.query.*;<br />
import org.basex.query.value.item.*;<br />
import org.basex.util.*;<br />
<br />
/**<br />
* This example inherits the {@link QueryModule} class and<br />
* implements the QueryResource interface.<br />
*/<br />
public class ContextModule extends QueryModule implements QueryResource {<br />
/**<br />
* Returns the name of the logged-in user.<br />
* @return user string<br />
*/<br />
@Requires(Permission.NONE)<br />
@Deterministic<br />
@ContextDependent<br />
public String user() {<br />
return queryContext.context.user.name;<br />
}<br />
<br />
/**<br />
* Converts the specified string to an integer.<br />
* @param value string to be converted<br />
* @return resulting integer<br />
* @throws QueryException query exception<br />
*/<br />
@Requires(Permission.NONE)<br />
@Deterministic<br />
public int toInt(final String value) throws QueryException {<br />
try {<br />
return Integer.parseInt(value);<br />
} catch(NumberFormatException ex) {<br />
throw new QueryException("Integer conversion failed: " + value);<br />
}<br />
}<br />
<br />
@Override<br />
public void close() {<br />
// defined in QueryResource interface, will be called after query evaluation<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
The result will look as follows:<br />
<br />
<syntaxhighlight lang="xml"><br />
<user>admin</admin><br />
<error>Integer conversion failed: abc</error><br />
</syntaxhighlight><br />
<br />
Please visit the XQuery 3.0 specification if you want to get more insight into<br />
[https://www.w3.org/TR/xpath-functions-31/#properties-of-functions function properties].<br />
<br />
==Updates==<br />
<br />
The {{Code|@Updating}} annotation can be applied to mark Java functions that perform write or update operations:<br />
<br />
<syntaxhighlight lang="java"><br />
@Updating<br />
public void backup() {<br />
// ...<br />
}<br />
</syntaxhighlight><br />
<br />
An XQuery expression will be handled as an [[XQuery Update#Updating Expressions|updating expression]] if it calls an updating Java function. In contrast to XQuery update operations, the Java code will immediately be executed, but the result will be cached as if {{Function|Update|update:output}} was called.<br />
<br />
The annotation is particularly helpful if combined with a lock annotation.<br />
<br />
==Locking==<br />
<br />
By default, a Java function will be executed in parallel with other code. If a Java function performs sensitive operations, it is advisable to explicitly lock the code.<br />
<br />
===Java Locks===<br />
<br />
Java provides a handful of mechanism to control the execution of code. The concurrent execution of functions can be avoided with the {{Code|synchronized}} keyword. For more complex scenarios, the Lock, Semaphore and Atomic classes can be brought into play.<br />
<br />
===XQuery Locks===<br />
<br />
If you want to synchronize the execution of your code with BaseX locks, you can take advantage of the {{Code|@Lock}} annotation:<br />
<br />
<syntaxhighlight lang="java"><br />
@Lock("HEAVYIO")<br />
public void read() {<br />
// ...<br />
}<br />
<br />
@Updating<br />
@Lock("HEAVYIO")<br />
public void write() {<br />
// ...<br />
}<br />
</syntaxhighlight><br />
<br />
If an XQuery expression invokes {{Code|write()}}, any other query that calls {{Code|write()}} or {{Code|read()}} needs to wait for the query to be finished. The {{Code|read()}} function can be run in parallel; whereas queries will be queued if {{Code|write()}} is called.<br />
<br />
More details on concurrent querying can be found in the article on [[Transaction Management]].<br />
<br />
==Data Types==<br />
<br />
===Conversion to Java===<br />
<br />
Before Java code is executed, the arguments are converted to Java values, depending on the addressed function or constructor parameters. The accepted Java types and the original XQuery types are depicted in the second and first column of the table below.<br />
<br />
If a numeric value is supplied for which no exact matching is defined, it is cast to the appropriate type unless it exceeds its limits. The following two function calls are equivalent:<br />
<br />
<syntaxhighlight lang="xquery"><br />
(: exact match :)<br />
Q{String}codePointAt('ABC', xs:int(1)),<br />
(: xs:byte and xs:integer casts :)<br />
Q{String}codePointAt('ABC', xs:byte(1)),<br />
Q{String}codePointAt('ABC', 1)<br />
</syntaxhighlight><br />
<br />
===Conversion to XQuery===<br />
<br />
By default, Java values with the most common types (as shown in the second and third column of the table) are converted to XQuery values. All other values are returned as ''Java items'', which are function items with a wrapped Java value. The results of constructor calls are always returned as Java items.<br />
<br />
The conversion of the wrapped Java value to XQuery is enforced by invoking the function item: Values in {{Code|Iterator}} and {{Code|Iterable}} instances (Lists, Sets and Collections) are converted to items, and maps are converted to XQuery maps:<br />
<br />
<syntaxhighlight lang="xquery"><br />
declare namespace Scanner = 'java:java.util.Scanner';<br />
let $scanner := Scanner:new("A B C") => Scanner:useDelimiter(" ")<br />
return $scanner()<br />
</syntaxhighlight><br />
<br />
If no conversion is defined, a string is returned, resulting from the {{Code|toString()}} method of the object. This method is also called if the string representation of a Java item is requested:<br />
<br />
<syntaxhighlight lang="xquery"><br />
(: returns the string representations of a HashMap and an ArrayList instance :)<br />
'Map: ' || Q{java.util.HashMap}new(),<br />
string(Q{java:java.util.ArrayList}new())<br />
</syntaxhighlight><br />
<br />
The conversion can be further controlled with the {{Option|WRAPJAVA}} option. The following values exist:<br />
<br />
{| class="wikitable"<br />
|- valign="top"<br />
! Value<br />
! Description<br />
|- valign="top"<br />
| {{Code|some}}<br />
| The default: Java values of the most common types are converted, others are wrapped into Java items.<br />
|- valign="top"<br />
| {{Code|none}}<br />
| All Java values are converted. If no conversion is defined, a string is returned, resulting from the {{Code|toString()}} method.<br />
|- valign="top"<br />
| {{Code|all}}<br />
| Java values are wrapped into Java items (excluding those inheriting the internal type {{Code|org.basex.query.value.Value}}).<br />
|- valign="top"<br />
| {{Code|instance}}<br />
| If the method of a class instance was called, the Java value is ignored and the instance is wrapped into a Java item. Otherwise, the Java value is returned.<br />
|- valign="top"<br />
| {{Code|void}}<br />
| Java values are ignored, and an empty sequence is returned instead.<br />
|}<br />
<br />
In the following example, the result of the first function – a char array – is wrapped and passed on to a {{Code|CharBuffer}} function. Without the option, the single-value array would be converted to an {{Code|xs:unsignedShort}} item and the second function call would fail:<br />
<br />
<syntaxhighlight lang="xquery"><br />
(: Without the pragma, the result of toChars would be converted to an xs:unsignedShort item, and the second function call would fail :)<br />
<br />
(# db:wrapjava all #) {<br />
Q{Character}toChars(xs:int(33))<br />
=> Q{java.nio.CharBuffer}wrap()<br />
}<br />
</syntaxhighlight><br />
<br />
The next example demonstrates a use case for the {{Code|instance}} option:<br />
<br />
<syntaxhighlight lang="xquery"><br />
(: Thanks to the pragma, the function calls can be chained :)<br />
<br />
declare namespace set = 'java:java.util.HashSet';<br />
let $set := (# db:wrapjava instance #) {<br />
set:new()<br />
=> set:add('1')<br />
=> set:add('2')<br />
}<br />
return $set()<br />
</syntaxhighlight><br />
<br />
The {{Code|void}} option is helpful if side-effecting methods return values that do not contribute to the final result:<br />
<br />
<syntaxhighlight lang="xquery"><br />
(: Without the pragma, 100 booleans would be returned by the FLWOR expression :)<br />
<br />
declare namespace set = 'java:java.util.HashSet';<br />
let $set := set:new()<br />
return (<br />
(# db:wrapjava void #) {<br />
for $i in 1 to 100<br />
return set:add($set, $i)<br />
},<br />
$set()<br />
)<br />
</syntaxhighlight><br />
<br />
The irrelevant results could also be swallowed with {{Function|Profiling|prof:void}}.<br />
<br />
{| class="wikitable"<br />
|- valign="top"<br />
! XQuery input<br />
! Expected or returned Java type<br />
! XQuery output<br />
|- valign="top"<br />
| <code>item()*</code> (no conversion)<br />
| <code>org.basex.query.value.Value</code><br />
| <code>item()*</code> (no conversion)<br />
|- valign="top"<br />
| <code>empty-sequence()</code><br />
| <code>null</code><br />
| <code>empty-sequence()</code><br />
|- valign="top"<br />
| <code>xs:string</code>, <code>xs:untypedAtomic</code><br />
| <code>String</code><br />
| <code>xs:string</code><br />
|- valign="top"<br />
| <code>xs:unsignedShort</code><br />
| <code>char</code>, <code>Character</code><br />
| <code>xs:unsignedShort</code><br />
|- valign="top"<br />
| <code>xs:boolean</code><br />
| <code>boolean</code>, <code>Boolean</code><br />
| <code>xs:boolean</code><br />
|- valign="top"<br />
| <code>xs:byte</code><br />
| <code>byte</code>, <code>Byte</code><br />
| <code>xs:byte</code><br />
|- valign="top"<br />
| <code>xs:short</code><br />
| <code>short</code>, <code>Short</code><br />
| <code>xs:short</code><br />
|- valign="top"<br />
| <code>xs:int</code><br />
| <code>int</code>, <code>Integer</code><br />
| <code>xs:int</code><br />
|- valign="top"<br />
| <code>xs:integer</code>, <code>xs:long</code><br />
| <code>long</code>, <code>Long</code><br />
| <code>xs:integer</code><br />
|- valign="top"<br />
| <code>xs:unsignedLong</code><br />
| <code>java.math.BigInteger</code><br />
| <code>xs:unsignedLong</code> (lossy)<br />
|- valign="top"<br />
| <code>xs:decimal</code><br />
| <code>java.math.BigDecimal</code><br />
| <code>xs:decimal</code><br />
|- valign="top"<br />
| <code>xs:float</code><br />
| <code>float</code>, <code>Float</code><br />
| <code>xs:float</code><br />
|- valign="top"<br />
| <code>xs:double</code><br />
| <code>double</code>, <code>Double</code><br />
| <code>xs:double</code><br />
|- valign="top"<br />
| <code>xs:QName</code><br />
| <code>javax.xml.namespace.QName</code><br />
| <code>xs:QName</code><br />
|- valign="top"<br />
| <code>xs:anyURI</code><br />
| <code>java.net.URI</code>, <code>java.net.URL</code><br />
| <code>xs:anyURI</code><br />
|- valign="top"<br />
| <code>xs:date</code><br />
| <code>javax.xml.datatype.XMLGregorianCalendar</code><br />
| <code>xs:date</code><br />
|- valign="top"<br />
| <code>xs:duration</code><br />
| <code>javax.xml.datatype.Duration</code><br />
| <code>xs:duration</code><br />
|- valign="top"<br />
| <code>node()</code><br />
| <code>org.w3c.dom.Node</code><br />
| <code>node()</code><br />
|- valign="top"<br />
| <code>array(xs:boolean)</code><br />
| <code>boolean[]</code><br />
| <code>xs:boolean*</code><br />
|- valign="top"<br />
| <code>array(xs:string)</code><br />
| <code>String[]</code><br />
| <code>xs:string*</code><br />
|- valign="top"<br />
| <code>array(xs:unsignedShort)</code><br />
| <code>char[]</code><br />
| <code>xs:unsignedShort*</code><br />
|- valign="top"<br />
| <code>array(xs:short)</code><br />
| <code>short[]</code><br />
| <code>xs:short*</code><br />
|- valign="top"<br />
| <code>array(xs:int)</code><br />
| <code>int[]</code><br />
| <code>xs:int*</code><br />
|- valign="top"<br />
| <code>array(xs:integer)</code>, <code>array(xs:long)</code><br />
| <code>long[]</code><br />
| <code>xs:integer*</code><br />
|- valign="top"<br />
| <code>array(xs:float)</code><br />
| <code>float[]</code><br />
| <code>xs:float*</code><br />
|- valign="top"<br />
| <code>array(xs:double)</code><br />
| <code>double[]</code><br />
| <code>xs:double*</code><br />
|- valign="top"<br />
| <code>Object[]</code> (others)<br />
| <code>item()*</code><br />
| <code>array(*)</code> (others)<br />
|- valign="top"<br />
| <code>map(*)</code><br />
| java.util.HashMap<br />
| <code>Wrapped Java object</code><br />
|}<br />
<br />
==URI Rewriting==<br />
<br />
Before a Java class or module is accessed, its namespace URI will be normalized:<br />
<br />
# If the URI is a URL:<br />
## colons will be replaced with slashes,<br />
## in the URI authority, the order of all substrings separated by dots is reversed, and<br />
## dots in the authority and the path are replaced by slashes. If no path exists, a single slash is appended.<br />
# Otherwise, if the URI is a URN, colons will be replaced with slashes.<br />
# Characters other than letters, dots and slashes will be replaced with dashes.<br />
# If the resulting string ends with a slash, the {{Code|index}} string is appended.<br />
<br />
If the resulting path has no file suffix, it may point to either an XQuery module or a Java archive:<br />
<br />
* {{Code|<nowiki>http://basex.org/modules/hello/World</nowiki>}} → {{Code|org/basex/modules/hello/World}}<br />
* {{Code|<nowiki>http://www.example.com</nowiki>}} → {{Code|com/example/www/index}}<br />
* {{Code|a/little/example}} → {{Code|a/little/example}}<br />
* {{Code|a:b:c}} → {{Code|a/b/c}}<br />
<br />
=Changelog=<br />
<br />
; Version 9.6<br />
* Updated: Java Bindings revised (new mappings, Java functiom items, {{Option|WRAPJAVA}} option).<br />
<br />
; Version 9.4<br />
* Added: Annotation for [[#Updates|updating functions]].<br />
* Updated: Single annotation for read and write locks.<br />
<br />
; Version 8.4<br />
* Updated: Rewriting rules<br />
<br />
;Version 8.2<br />
* Added: [[#URI Rewriting|URI Rewriting]]: support for URNs<br />
<br />
; Version 8.0<br />
* Added: {{Code|QueryResource}} interface, called after a query has been fully evaluated.<br />
<br />
; Version 7.8<br />
* Added: Java locking annotations<br />
* Updated: {{Code|context}} variable has been split into {{Code|queryContext}} and {{Code|staticContext}}.<br />
<br />
; Version 7.2.1<br />
* Added: import of Java modules, context awareness<br />
* Added: [[#Packaging|Packaging]], [[#URI Rewriting|URI Rewriting]]</div>Andy Buncehttps://docs.basex.org/index.php?title=Store_Module&diff=15634Store Module2022-05-05T14:26:20Z<p>Andy Bunce: remove excess ")"</p>
<hr />
<div>This [[Module Library|XQuery Module]] provides functions to organize values in a main-memory cache.<br />
<br />
Caching is advisable if data (a system configuration, maps serving as indexes) needs to be repeatedly accessed. The cache is persistent: Contents will be written to disk at shutdown time, and the serialized cache will be retrieved from disk as soon as the cache is used for the first time. The cache will be stored in a binary {{Code|cache.basex}} file in the database directory.<br />
<br />
In addition, custom caches can be read and written. Custom cache files use the filename pattern {{Code|cache-NAME.basex}}. The implicit write of the standard cache at shutdown time will be disabled if a custom cache is used.<br />
<br />
Functions of this module are non-deterministic and side-effecting: Updates will immediately be visible, and a repeated call of the same function may yield different results if the contents of the cache have changed.<br />
<br />
=Conventions=<br />
<br />
All functions and errors in this module are assigned to the <code><nowiki>http://basex.org/modules/cache</nowiki></code> namespace, which is statically bound to the {{Code|cache}} prefix.<br/><br />
<br />
=Cache Entries=<br />
<br />
==cache:get==<br />
<br />
{| width='100%'<br />
|-<br />
| width='120' | '''Signatures'''<br />
|{{Func|cache:get|$key as xs:string|item()*}}<br/ ><br />
|-<br />
|'''Summary'''<br />
|Retrieves an entry from the cache with the given {{Code|$key}}. If the addressed entry does not exist, an empty sequence is returned.<br />
|}<br />
<br />
==cache:put==<br />
<br />
{| width='100%'<br />
|-<br />
| width='120' | '''Signatures'''<br />
|{{Func|cache:put|$key as xs:string, $value as item()*|empty-sequence()}}<br/ ><br />
|-<br />
|'''Summary'''<br />
|Stores an entry with the given {{Code|$key}} and {{Code|$value}} in the cache:<br />
* If the value is an empty sequence, the entry is removed.<br />
* If a value refers to an opened database or is [[Lazy Module|a lazy item]], its contents are materialized in main memory.<br />
* Values with function items are rejected.<br />
|}<br />
<br />
==cache:get-or-put==<br />
<br />
{| width='100%'<br />
|-<br />
| width='120' | '''Signatures'''<br />
|{{Func|cache:get-or-put|$key as xs:string, $put as function() as item()*|item()*}}<br/ ><br />
|-<br />
|'''Summary'''<br />
|Retrieves an entry from the cache with the given {{Code|$key}}. The {{Code|$put}} function will only be invoked if the entry does not exist, and its result will be stored and returned instead.<br />
|}<br />
<br />
==cache:remove==<br />
<br />
{| width='100%'<br />
|-<br />
| width='120' | '''Signatures'''<br />
|{{Func|cache:remove|$key as xs:string|empty-sequence()}}<br/ ><br />
|-<br />
|'''Summary'''<br />
|Removes an entry with the given {{Code|$key}} from the cache. No error will be raised if an addressed entry does not exist.<br />
|}<br />
<br />
==cache:keys==<br />
<br />
{| width='100%'<br />
|-<br />
| width='120' | '''Signatures'''<br />
|{{Func|cache:keys||xs:string*}}<br />
|-<br />
|'''Summary'''<br />
|Lists the names of all keys.<br />
|}<br />
<br />
==cache:clear==<br />
<br />
{| width='100%'<br />
|-<br />
| width='120' | '''Signatures'''<br />
|{{Func|cache:clear||empty-sequence()}}<br/ ><br />
|-<br />
|'''Summary'''<br />
|Resets the cache by removing all its entries.<br />
|}<br />
<br />
=Cache Operations=<br />
<br />
==cache:read==<br />
<br />
{| width='100%'<br />
|-<br />
| width='120' | '''Signatures'''<br />
|{{Func|cache:read||empty-sequence()}}<br/ >{{Func|cache:read|$name as xs:string|empty-sequence()}}<br />
|-<br />
|'''Summary'''<br />
|Retrieves the standard cache from disk, or a custom cache if a {{Code|$name}} is supplied.<br />
|-<br />
|'''Errors'''<br />
|{{Error|io|#Errors}} The cache could not be read.<br/>{{Error|name|#Errors}} The specified name is invalid.<br/>{{Error|not-found|#Errors}} A cache with the specified name does not exist.<br />
|}<br />
<br />
==cache:write==<br />
<br />
{| width='100%'<br />
|-<br />
| width='120' | '''Signatures'''<br />
|{{Func|cache:write||empty-sequence()}}<br/ >{{Func|cache:write|$name as xs:string|empty-sequence()}}<br />
|-<br />
|'''Summary'''<br />
|Writes the standard cache to disk, or to a custom cache file if a {{Code|$name}} is supplied. If the standard cache is empty, the cache file will be deleted.<br />
|-<br />
|'''Errors'''<br />
|{{Error|io|#Errors}} The cache could not be written.<br/>{{Error|name|#Errors}} The specified name is invalid.<br />
|}<br />
<br />
==cache:list==<br />
<br />
{| width='100%'<br />
|-<br />
| width='120' | '''Signatures'''<br />
|{{Func|cache:list||xs:string*}}<br />
|-<br />
|'''Summary'''<br />
|Lists the names of all custom caches.<br />
|}<br />
<br />
==cache:delete==<br />
<br />
{| width='100%'<br />
|-<br />
| width='120' | '''Signatures'''<br />
|{{Func|cache:delete|$name as xs:string|empty-sequence()}}<br />
|-<br />
|'''Summary'''<br />
|Deletes a custom cache from disk.<br />
|-<br />
|'''Errors'''<br />
|{{Error|name|#Errors}} The specified name is invalid.<br/>{{Error|not-found|#Errors}} A cache with the specified name does not exist.<br />
|}<br />
<br />
=Examples=<br />
<br />
'''Use Case 1: Create/update a system configuration in a running BaseX server instance:<br />
<br />
<syntaxhighlight lang="xquery"><br />
(: store an integer :)<br />
cache:put('version', 1),<br />
(: retrieve existing or new value, store an element :)<br />
let $license := cache:get-or-put('license', function() { 'free' })<br />
return cache:put('info', <info>{ $license = 'free' ?? 'Free' !! 'Professional' } License</info>),<br />
(: store a map :)<br />
cache:put('data', map { 'year': 2022 }),<br />
(: serialize configuration to disk :)<br />
cache:write()<br />
</syntaxhighlight><br />
<br />
The configuration can be requested by further operations, e.g. a client request:<br />
<br />
<syntaxhighlight lang="xquery"><br />
cache:get('version')<br />
</syntaxhighlight><br />
<br />
The cache will still be available if BaseX is restarted until it is cleared.<br />
<br />
'''Use Case 2: Create index for fast lookup operations in the GUI:<br />
<br />
<syntaxhighlight lang="xquery"><br />
let $map := map:merge(<br />
for $country in db:open('factbook')//country<br />
for $religion in $country//religions<br />
group by $religion<br />
return map:entry($religion, data($country/@name))<br />
)<br />
return cache:put('religions', $map)<br />
</syntaxhighlight><br />
<br />
A subsequent query can be used to access its contents:<br />
<br />
<syntaxhighlight lang="xquery"><br />
cache:get('religions')?Buddhism<br />
</syntaxhighlight><br />
<br />
Note that the cache will eventually be written to disk unless it is invalidated before closing the GUI.<br />
<br />
=Errors=<br />
<br />
{| class="wikitable" width="100%"<br />
! width="110"|Code<br />
|Description<br />
|-<br />
|{{Code|io}}<br />
| The cache could not be read or written.<br />
|-<br />
|{{Code|name}}<br />
| The specified name is invalid.<br />
|-<br />
|{{Code|not-found}}<br />
| A cache with the specified name does not exist.<br />
|}<br />
<br />
=Changelog=<br />
<br />
The module was introduced with Version 10.</div>Andy Buncehttps://docs.basex.org/index.php?title=Job_Module&diff=13990Job Module2018-08-20T13:22:00Z<p>Andy Bunce: contents entry for job:services</p>
<hr />
<div>This [[Module Library|XQuery Module]] provides functions for organizing scheduled, queued, running and cached jobs. Jobs can be commands, queries, client or HTTP requests.<br />
<br />
=Conventions=<br />
<br />
All functions in this module are assigned to the <code><nowiki>http://basex.org/modules/jobs</nowiki></code> namespace, which is statically bound to the {{Code|jobs}} prefix. Errors will be bound to the same prefix.<br />
<br />
=Services=<br />
<br />
Jobs can additionally be registered as persistent services. An additional {{Code|service}} option has been added to the options list of {{Function|Jobs|jobs:eval}} and {{Function|Jobs|jobs:invoke}}:<br />
<br />
<pre class="brush:xquery"><br />
(: register job, which will be run every day at 1 am :)<br />
jobs:eval('db:drop("tmp")', (), map { 'id':'cleanup', 'start':'01:00:00', 'interval':'P1D', 'service': true() }),<br />
<br />
(: list registered services :)<br />
jobs:services(),<br />
(: result: <job base-uri="..." id="cleanup" interval="P1D" start="01:00:00">db:drop("tmp")</job> :)<br />
<br />
(: unregister job :)<br />
jobs:stop('cleanup', map { 'service': true() })<br />
</pre><br />
<br />
'''Some more notes:'''<br />
<br />
* All registered jobs will be scheduled for evaluation when the BaseX server or BaseX HTTP server is started.<br />
* If a job service is outdated (e.g. because a supplied end time has been exceeded), it will be removed from the jobs file at startup time.<br />
* Job services can be updated: If a new job is registered, and if there is already a job with the same id, the old entry will be replaced.<br />
* The job definitions are stored in a {{Code|jobs.xml}} file in the database directory. It can also be edited manually.<br />
<br />
=Basic Functions=<br />
<br />
==jobs:current==<br />
<br />
{| width='100%'<br />
|-<br />
| width='120' | '''Signatures'''<br />
|{{Func|jobs:current||xs:string}}<br />
|-<br />
| '''Summary'''<br />
|Returns the id of the current job.<br />
|}<br />
<br />
==jobs:list==<br />
<br />
{| width='100%'<br />
|-<br />
| width='120' | '''Signatures'''<br />
|{{Func|jobs:list||xs:string*}}<br />
|-<br />
| '''Summary'''<br />
|Returns the ids of all jobs that are currently registered. The list includes scheduled, queued, running, stopped, and finished jobs with cached results.<br />
|-<br />
| '''Examples'''<br />
| <code>jobs:list()</code> returns the same job id as {{Function|Jobs|jobs:current}} if no other job is registered.<br />
|}<br />
<br />
==jobs:list-details==<br />
<br />
{| width='100%'<br />
|-<br />
| width='120' | '''Signatures'''<br />
|{{Func|jobs:list-details||element(job)*}}<br/>{{Func|jobs:list-details|$id as xs:string|element(job)*}}<br />
|-<br />
| '''Summary'''<br />
|Returns information on all jobs that are currently registered, or on a job with the specified {{Code|$id}} (or an empty sequence if this job is not found). The list includes scheduled, queued, running jobs, and cached jobs. A string representation of the job, or its URI, will be returned as value. The returned elements have additional attributes:<br />
* <code>id</code>: job id<br />
* <code>type</code>: type of the job (command, query, REST, RESTXQ, etc.)<br />
* <code>state</code>: current state of the job (scheduled, queued, running, or cached)<br />
* <code>user</code>: the user who started the job<br />
* <code>duration</code>: evaluation time (for running and cached jobs)<br />
* <code>start</code>: dateTime string with next start (for jobs that will be executed repeatedly)<br />
|-<br />
| '''Examples'''<br />
| <code>jobs:list-details()</code> returns information on the currently running job and possibly others:<br />
<pre class="brush:xml"><br />
<job id="job1" type="XQuery" state="running" user="admin" duration="PT0.001S"><br />
XQUERY jobs:list-details()<br />
</job><br />
</pre><br />
|}<br />
<br />
<br />
==jobs:finished==<br />
<br />
{| width='100%'<br />
|-<br />
| width='120' | '''Signatures'''<br />
|{{Func|jobs:finished|$id as xs:string|xs:boolean}}<br />
|-<br />
| '''Summary'''<br />
|Indicates if the evaluation of an already running job with the specified {{Code|$id}} has finished. As the ids of finished jobs will usually be discarded, unless caching is enabled, the function will also return <code>true</code> for unknown jobs.<br />
* <code>false</code> indicates that the job id is scheduled, queued, or currently running.<br />
* <code>true</code> will be returned if the job has either finished, or if the id is unknown (because the ids of all finished jobs will not be cached).<br />
|}<br />
<br />
==jobs:services==<br />
<br />
{| width='100%'<br />
|-<br />
| width='120' | '''Signatures'''<br />
|{{Func|jobs:services||element(job)*}}<br />
|-<br />
| '''Summary'''<br />
|Returns a list of all jobs that have been persistently registered as [[#Services|Services]].<br />
|-<br />
| '''Errors'''<br />
|{{Error|services|#Errors}} Registered services cannot be parsed.<br/><br />
|}<br />
<br />
=Execution=<br />
<br />
Asynchronous query execution is recommendable if a client does not, or cannot, wait until a request is fully processed. This is e. g. the case with web browsers, which will usually cancel a request after a specific timeout. In such cases, you can use asynchronous execution to trigger another server-side process, which will start the time-consuming process, and fetch the result later on as soon as it is available.<br />
<br />
==jobs:eval==<br />
<br />
{| width='100%'<br />
|-<br />
| width='120' | '''Signatures'''<br />
|{{Func|jobs:eval|$query as xs:string|xs:string}}<br />{{Func|jobs:eval|$query as xs:string, $bindings as map(*)?|xs:string}}<br />{{Func|jobs:eval|$query as xs:string, $bindings as map(*)?, $options as map(*)?|xs:string}}<br /><br />
|-<br />
| '''Summary'''<br />
|Schedules the evaluation of the supplied {{Code|$query}} and returns a query id. The query will be queued, and the result will optionally be cached. Queries can be updating. Variables and context items can be declared via {{Code|$bindings}} (see [[XQuery Module#xquery:eval|xquery:eval]] for more details). The following {{Code|$options}} can be supplied:<br />
* {{Code|cache}}: indicates if the query result will be cached or ignored (default: <code>false</code>):<br />
** The result will be cached in main-memory until it is fetched via [[#jobs:result|jobs:result]], or until {{Option|CACHETIMEOUT}} is exceeded.<br />
** If the query raises an error, it will be cached and returned instead.<br />
* {{Code|start}}: a dayTimeDuration, time or dateTime can be specified to delay the execution of the query:<br />
** If a dayTimeDuration is specified, the query will be queued after the specified duration has passed. Examples for valid values are: <code>P1D</code> (1 day), <code>PT5M</code> (5 minutes), <code>PT0.1S</code> (100 ms). An error will be raised if a negative value is specified.<br />
** If a time is specified, the query will be executed at this time of the day. Examples for valid times are: <code>02:00:00</code> (2am local time), <code>12:00:00Z</code> (noon, UTC). If the time lies in the past, the query will be executed the next day.<br />
** If a dateTime is specified, the query will be executed at this date. Examples for valid values are: <code>2018-12-31T23:59:59</code> (New Year's Eve 2018, close to midnight). An error will be raised if the specified time lies in the past.<br />
* {{Code|interval}}: a dayTimeDuration string can be specified to execute the query periodically. An error is raised if the specified interval is less than one second (<code>PT1S</code>). If the next scheduled call is due, and if a query with the same id is still running, it will be skipped.<br />
* {{Code|end}}: scheduling can be stopped after a given time or duration. The string format is the same as for {{Code|start}}. An error is raised if the resulting end time is smaller than the start time.<br />
* {{Code|base-uri}}: sets the [https://www.w3.org/TR/xquery-31/#dt-static-base-uri base-uri property] for the query. This URI will be used when resolving relative URIs, such as with {{Code|fn:doc}}.<br />
* {{Code|id}}: sets a custom job id. The id must not start with the standard <code>job</code> prefix, and it can only be assigned if no job with the same name exists.<br />
* {{Code|service}}: additionally registers the job as [[#Services|service]].<br />
|-<br />
| '''Errors'''<br />
|{{Error|overflow|#Errors}} Query execution is rejected, because too many jobs are queued or being executed. {{Option|CACHETIMEOUT}} can be decreased if the default setting is too restrictive.<br/>{{Error|range|#Errors}} A specified time or duration is out of range.<br/>{{Error|id|#Errors}} The specified id is invalid or has already been assigned.<br/>{{Error|options|#Errors}} The specified options are conflicting.<br />
|-<br />
| '''Examples'''<br />
|<br />
* Cache query result. The returned id can be used to pick up the result with [[#jobs:result|jobs:result]]:<br />
<pre class='brush:xquery'><br />
jobs:eval("1+3", (), map { 'cache': true() })<br />
</pre><br />
* A happy birthday mail will be sent at the given date:<br />
<pre class="brush:xquery"><br />
jobs:eval("import module namespace mail='mail'; mail:send('Happy birthday!')",<br />
(), map { 'start': '2018-09-01T06:00:00' })}}<br />
</pre><br />
* The following [[RESTXQ]] functions can be called to execute a query at 2 am every day. An id will be returned by the first function, which can be used to stop the scheduler via the second function:<br />
<pre class='brush:xquery'><br />
declare %rest:POST("{$query}") %rest:path('/start-scheduling') function local:start($query) {<br />
jobs:eval($query, (), map { 'start': '02:00:00', 'interval': 'P1D' })<br />
};<br />
declare %rest:path('/stop-scheduling/{$id}') function local:stop($id) {<br />
jobs:stop($id)<br />
};<br />
</pre><br />
* Query execution is scheduled for every second, and for 10 seconds in total. As the query itself will take 1.5 seconds, it will only be executed every second time:<br />
<pre class="brush:xquery"><br />
jobs:eval("prof:sleep(1500)", (), map { 'interval': 'PT1S', 'end': 'PT10S' })<br />
</pre><br />
* The following expression, if stored as a file, calls and evaluates itself every 5 seconds:<br />
<pre class="brush:xquery"><br />
jobs:eval(<br />
file:read-text(static-base-uri()),<br />
map { },<br />
map { 'start': 'PT5S' }<br />
)<br />
</pre><br />
|}<br />
<br />
==jobs:invoke==<br />
<br />
{| width='100%'<br />
|-<br />
| width='120' | '''Signatures'''<br />
|{{Func|jobs:invoke|$uri as xs:string|xs:string}}<br />{{Func|jobs:invoke|$uri as xs:string, $bindings as map(*)?|xs:string}}<br />{{Func|jobs:invoke|$uri as xs:string, $bindings as map(*)?, $options as map(*)?|xs:string}}<br /><br />
|-<br />
| '''Summary'''<br />
|Schedules the evaluation of the XQuery expression located at {{Code|$uri}} and returns a query id. For further details, see [[#jobs:eval|jobs:eval]].<br />
|-<br />
| '''Errors'''<br />
|{{Error|overflow|#Errors}} Query execution is rejected, because too many jobs are queued or being executed. {{Option|CACHETIMEOUT}} can be decreased if the default setting is too restrictive.<br/>{{Error|range|#Errors}} A specified time or duration is out of range.<br/>{{Error|id|#Errors}} The specified id is invalid or has already been assigned.<br/>{{Error|options|#Errors}} The specified options are conflicting.<br />
|-<br />
| '''Examples'''<br />
| Run XQuery expression that may perform some cleanups:<br />
<pre class='brush:xquery'><br />
jobs:invoke("cleanup.xq", (), ())<br />
</pre><br />
|}<br />
<br />
==jobs:result==<br />
<br />
{| width='100%'<br />
|-<br />
| width='120' | '''Signatures'''<br />
|{{Func|jobs:result|$id as xs:string|item()*}}<br />
|-<br />
| '''Summary'''<br />
|Returns the cached result of a job with the specified job {{Code|$id}}:<br />
* Results can only be retrieved once. After retrieval, the cached result will be dropped.<br />
* If the original job has raised an error, the cached error will be raised instead.<br />
|-<br />
| '''Errors'''<br />
|{{Error|running|#Errors}} the job is still running.<br/>{{Error|unknown|#Errors}} the supplied id is unknown: The id is unknown, or the result has already been retrieved.<br/><br />
|-<br />
| '''Examples'''<br />
|<br />
* The following [[RESTXQ]] function will either return the result of a previously started job or raise an error:<br />
<pre class='brush:xquery'><br />
declare %rest:path('/result/{$id}') function local:result($id) {<br />
jobs:result($id)<br />
};<br />
</pre><br />
* The following query demonstrates how the results of an asynchronously executed query can be returned within the same query:<br />
<pre class='brush:xquery'><br />
let $query := jobs:eval('(1 to 10000000)[. = 1]', map{}, map{ 'cache': true() })<br />
return (<br />
jobs:wait($query),<br />
jobs:result($query)<br />
)<br />
</pre><br />
Please note that queries of this kind can cause deadlocks. For example, if both the original query and the query to be executed asynchronously perform updates on the same database, the second query would only be run after the first one has been executed, and the first query will wait forever. This is why you should avoid this pattern in practice and resort to [[XQuery Module#xquery:fork-join|xquery:fork-join]] if you want to do things in parallel.<br />
|}<br />
<br />
==jobs:stop==<br />
<br />
{| width='100%'<br />
|-<br />
| width='120' | '''Signatures'''<br />
|{{Func|jobs:stop|$id as xs:string|empty-sequence()}}<br />
|-<br />
| '''Summary'''<br />
|Triggers the cancelation of a job with the specified {{Code|$id}}, drops the cached result of a query, or cancels a scheduled job. Unknown ids are ignored. All jobs are gracefully stopped; it is up to the process to decide when it is safe to shut down. The following {{Code|$options}} can be supplied:<br />
* {{Code|service}}: additionally removes the job from the [[#Services|job services]] list.<br />
|-<br />
| '''Examples'''<br />
| <code>jobs:list()[. != jobs:current()] ! jobs:stop(.)</code> stops and discards all jobs except for the current one.<br />
|}<br />
<br />
==jobs:wait==<br />
<br />
{| width='100%'<br />
|-<br />
| width='120' | '''Signatures'''<br />
|{{Func|jobs:wait|$id as xs:string|empty-sequence()}}<br />
|-<br />
| '''Summary'''<br />
|Waits for the completion of a job with the specified {{Code|$id}}:<br />
* The function will terminate immediately if the job id is unknown. This is the case if a future job has not been queued yet, or if the id has already been discarded after job evaluation.<br />
* If the function is called with the id of a queued job, or repeatedly executed job, it may stall and never terminate.<br />
|-<br />
| '''Errors'''<br />
|{{Error|self|#Errors}} The current job is addressed.<br/><br />
|}<br />
<br />
=Errors=<br />
<br />
{| class="wikitable" width="100%"<br />
! width="110"|Code<br />
|Description<br />
|-<br />
|{{Code|options}}<br />
| The specified options are conflicting.<br />
|-<br />
|{{Code|id}}<br />
| The specified id is invalid or has already been assigned.<br />
|-<br />
|{{Code|overflow}}<br />
| Too many queries or query results are queued.<br />
|-<br />
|{{Code|range}}<br />
| A specified time or duration is out of range.<br />
|-<br />
|{{Code|running}}<br />
| A query is still running.<br />
|-<br />
|{{Code|self}}<br />
| The current job cannot be addressed.<br />
|-<br />
|{{Code|service}}<br />
| Registered services cannot be parsed, added or removed.<br />
|-<br />
|{{Code|unknown}}<br />
| The supplied query id is unknown or not available anymore.<br />
|}<br />
<br />
=Changelog=<br />
<br />
;Version 9.0<br />
<br />
* Added: {{Function|Jobs|jobs:invoke}}, [[#Services|Services]]<br />
<br />
;Version 8.6<br />
<br />
* Updated: [[#jobs:eval|jobs:eval]]: <code>id</code> option added.<br />
<br />
The module was introduced with Version 8.5.</div>Andy Buncehttps://docs.basex.org/index.php?title=CSV_Module&diff=13820CSV Module2018-03-26T13:35:20Z<p>Andy Bunce: update format allowed options</p>
<hr />
<div>This [[Module Library|XQuery Module]] contains a single function to parse CSV input. [http://en.wikipedia.org/wiki/Comma-separated_values CSV] (comma-separated values) is a popular representation for tabular data, exported e. g. from Excel.<br />
<br />
=Conventions=<br />
<br />
{{Mark|Updated with Version 9.0:}}<br />
<br />
All functions and errors in this module are assigned to the <code><nowiki>http://basex.org/modules/csv</nowiki></code> namespace, which is statically bound to the {{Code|csv}} prefix.<br/><br />
<br />
==Conversion==<br />
<br />
===XML: Direct, Attributes===<br />
<br />
If the {{Code|direct}} or {{Code|attributes}} format is chosen, a CSV string is converted to XML:<br />
<br />
* The resulting XML document has a {{Code|<csv>}} root element.<br />
* Rows are represented via {{Code|<record>}} elements.<br />
* Fields are represented via {{Code|<entry>}} elements. The value of a field is represented as text node.<br />
* If the {{Code|header}} option is set to {{Code|true}}, the first text line is parsed as table header, and the {{Code|<entry>}} elements are replaced with the field names:<br />
** Empty names are represented by a single underscore ({{Code|_}}), and characters that are not valid in element names are replaced with underscores or (when invalid as first character of an element name) prefixed with an underscore.<br />
** If the {{Code|lax}} option is set to {{Code|false}}, invalid characters will be rewritten to an underscore and the character’s four-digit Unicode, and underscores will be represented as two underscores ({{Code|__}}). The resulting element names may be less readable, but can always be converted back to the original field names.<br />
* If {{Code|format}} is set to {{Code|attributes}}, field names will be stored in name attributes.<br />
<br />
'''A little advice''': in the Database Creation dialog of the GUI, if you select CSV Parsing and switch to the ''Parsing'' tab, you can see the effects of some of the conversion options.<br />
<br />
===XQuery===<br />
<br />
This format has been introduced with {{Version|9.0}}. It is more flexible and light-weight than the old, discarded {{Code|map}} format.<br />
<br />
With the {{Code|xquery}} format, CSV records are converted to a sequence of arrays:<br />
<br />
* The resulting value will be a map with a {{Code|records}} and an optional {{Code|names}} key.<br />
* Records are organized as a sequence of arrays. A single array contains the entries of a single record.<br />
* The column names will be available if {{Code|header}} option is set to {{Code|true}}.<br />
<br />
The CSV map can e.g. be accessed as follows:<br />
<br />
* <code>$csv?records[5]</code> returns all entries of the 5th record (row)<br />
* <code>$csv?records(2)</code> returns all entries of the 2nd field (column)<br />
* <code>$csv?names?*</code> returns the names of all fields (if available)<br />
* Return enumerated strings for all records:<br />
<pre class="brush:xquery"><br />
for $record at $pos in $csv?records<br />
return $pos || ". " || string-join($record?*, ', ')<br />
</pre><br />
<br />
The resulting representation consumes less memory than XML-based formats, and values can be directly accessed without conversion. Thus, it is recommendable for very large inputs and for efficient ad-hoc processing.<br />
<br />
==Options==<br />
<br />
In the following table, all available options are listed. The Excel column indicates what are the preferred options for data that is to be imported, or has been exported from Excel.<br />
<br />
{| class="wikitable sortable" width="100%"<br />
|- valign="top"<br />
! width="140" | Option<br />
! width="50%" | Description<br />
! Allowed<br />
! Default<br />
! Excel<br />
|- valign="top"<br />
| {{Code|separator}}<br />
| Defines the character which separates the values of a single record.<br />
| {{Code|comma}}, {{Code|semicolon}}, {{Code|colon}}, {{Code|tab}}, {{Code|space}} or a ''single character''<br />
| {{Code|comma}}<br />
| {{Code|semicolon}}<br />
|- valign="top"<br />
| {{Code|header}}<br />
| Indicates if the first line of the parsed or serialized CSV data is a table header.<br />
| {{Code|yes}}, {{Code|no}}<br />
| {{Code|no}}<br />
|<br />
|- valign="top"<br />
| {{Code|format}}<br />
| Specifies the format of the XML data:<br/><br />
* With {{Code|direct}} conversion, field names are represented as element names<br />
* With {{Code|attributes}} conversion, field names are stored in {{Code|name}} attributes<br />
* With {{Code|xquery}} conversion, the input is converted to an XQuery map<br />
| {{Code|direct}}, {{Code|attributes}}, {{Code|xquery}}<br />
| {{Code|direct}}<br />
|<br />
|- valign="top"<br />
| {{Code|lax}}<br />
| Specifies if a lax approach is used to convert QNames to JSON names.<br />
| {{Code|yes}}, {{Code|no}}<br />
| {{Code|yes}}<br />
| {{Code|no}}<br />
|- valign="top"<br />
| {{Code|quotes}}<br />
| Specifies how quotes are parsed:<br />
* Parsing: If the option is enabled, quotes at the start and end of a value will be treated as control characters. Separators and newlines within the quotes will be adopted without change.<br />
* Serialization: If the option is enabled, the value will be wrapped with quotes. A quote character in the value will be encoded according to the rules of the {{Code|backslashes}} option.<br />
| {{Code|yes}}, {{Code|no}}<br />
| {{Code|yes}}<br />
| {{Code|yes}}<br />
|- valign="top"<br />
| {{Code|backslashes}}<br />
| Specifies how quotes and other characters are escaped:<br />
* Parsing: If the option is enabled, {{Code|\r}}, {{Code|n}} and {{Code|\t}} will be replaced with the corresponding control characters. All other escaped characters will be adopted as literals (e.g.: {{Code|\"}} → {{Code|"}}). If the option is disabled, two consecutive quotes will be replaced with a single quote (unless {{Code|quotes}} is enabled and the quote is the first or last character of a value).<br />
* Serialization: If the option is enabled, {{Code|\r}}, {{Code|n}}, {{Code|\t}}, {{Code|"}} and the separator character will be encoded with a backslash. If the option is disabled, quotes will be duplicated.<br />
| {{Code|yes}}, {{Code|no}}<br />
| {{Code|no}}<br />
| {{Code|no}}<br />
|}<br />
<br />
=Functions=<br />
<br />
==csv:parse==<br />
<br />
{| width='100%'<br />
|-<br />
| width='120' | '''Signatures'''<br />
|{{Func|csv:parse|$input as xs:string|document-node(element(csv))}}<br/>{{Func|csv:parse|$input as xs:string, $options as map(*)?|item()}}<br />
|-<br />
| '''Summary'''<br />
|Converts the CSV data specified by {{Code|$input}} to an XML document or a map. The {{Code|$options}} argument can be used to control the way the input is converted.<br />
|-<br />
| '''Errors'''<br />
|{{Error|parse|#Errors}} the input cannot be parsed.<br />
|}<br />
<br />
==csv:serialize==<br />
<br />
{| width='100%'<br />
|-<br />
| width='120' | '''Signatures'''<br />
|{{Func|csv:serialize|$input as item()?|xs:string}}<br/>{{Func|csv:serialize|$input as item()?, $options as map(*)?|xs:string}}<br />
|-<br />
| '''Summary'''<br />
|Serializes the specified {{Code|$input}} as CSV, using the specified {{Code|$options}}, and returns the result as string.<br />
Values can also be serialized as CSV with the standard [[Serialization]] feature of XQuery:<br />
* The parameter {{Code|method}} needs to be set to {{Code|csv}}, and<br />
* the options presented in this article need to be assigned to the {{Code|csv}} parameter.<br />
|-<br />
| '''Errors'''<br />
|{{Error|serialize|#Errors}} the input cannot be serialized.<br />
|}<br />
<br />
=Examples=<br />
<br />
'''Example 1:''' Converts CSV data to XML, interpreting the first row as table header:<br />
<br />
'''Input''' {{Code|addressbook.csv}}:<br />
<pre class="brush:xml"><br />
Name,First Name,Address,City<br />
Huber,Sepp,Hauptstraße 13,93547 Hintertupfing<br />
</pre><br />
<br />
'''Query:'''<br />
<pre class="brush:xquery"><br />
let $text := file:read-text('addressbook.csv')<br />
return csv:parse($text, map { 'header': true() })<br />
</pre><br />
<br />
'''Result:'''<br />
<pre class="brush:xml"><br />
<csv><br />
<record><br />
<Name>Huber</Name><br />
<First_Name>Sepp</First_Name><br />
<Address>Hauptstraße 13</Address><br />
<City>93547 Hintertupfing</City><br />
</record><br />
</csv><br />
</pre><br />
'''<br />
<br />
'''Example 2:''' Converts some CSV data to XML and back, and checks if the input and output are equal. The expected result is {{Code|true}}:<br />
<br />
'''Query:'''<br />
<pre class="brush:xquery"><br />
let $options := map { 'lax': false() }<br />
let $input := file:read-text('some-data.csv')<br />
let $output := $input => csv:parse($options) => csv:serialize($options)<br />
return $input eq $output<br />
</pre><br />
<br />
'''Example 3:''' Converts CSV data to XQuery and returns distinct column values:<br />
<br />
'''Query:'''<br />
<pre class="brush:xquery"><br />
let $text := ``[Name,City<br />
Jack,Chicago<br />
Jack,Washington<br />
John,New York<br />
]``<br />
let $options := map { 'format': 'xquery', 'header': true() }<br />
let $csv := csv:parse($text, $options)<br />
return (<br />
'Distinct values:',<br />
let $records := $csv('records')<br />
for $name at $pos in $csv('names')?*<br />
let $values := $records($pos)<br />
return (<br />
'* ' || $name || ': ' || string-join(distinct-values($values), ', ')<br />
)<br />
)<br />
</pre><br />
<br />
'''Result:'''<br />
<pre class="brush:xquery"><br />
Distinct values:<br />
* Name: Jack, John<br />
* City: Chicago, Washington, New York<br />
</pre><br />
<br />
=Errors=<br />
<br />
{{Mark|Updated with Version 9.0:}}<br />
<br />
{| class="wikitable" width="100%"<br />
! width="110"|Code<br />
|Description<br />
|-<br />
|{{Code|parse}}<br />
| The input cannot be parsed.<br />
|-<br />
|{{Code|serialize}}<br />
| The node cannot be serialized.<br />
|}<br />
<br />
=Changelog=<br />
<br />
;Version 9.0<br />
<br />
* Added: {{Code|xquery}} option<br />
* Removed: {{Code|map}} option<br />
* Updated: error codes updated; errors now use the module namespace<br />
<br />
;Version 8.6<br />
<br />
* Updated: [[#Options|Options]]: improved Excel compatibility<br />
<br />
;Version 8.0<br />
<br />
* Added: {{Code|backslashes}} option<br />
<br />
;Version 7.8<br />
<br />
* Updated: [[#csv:parse|csv:parse]] now returns a document node instead of an element, or an XQuery map if {{Code|format}} is set to {{Code|map}}.<br />
* Added: {{Code|format}} and {{Code|lax}} options<br />
<br />
The module was introduced with Version 7.7.2.</div>Andy Buncehttps://docs.basex.org/index.php?title=XQuery_Recipes&diff=13242XQuery Recipes2017-07-08T21:41:56Z<p>Andy Bunce: update fold-left syntax</p>
<hr />
<div>This page contains code snippets that mainly originate from our [https://mailman.uni-konstanz.de/mailman/listinfo/basex-talk basex-talk] mailing list.<br />
<br />
== Compact Notations ==<br />
<br />
<code>if</code>/<code>not</code>/<code>else</code> constructs can look pretty verbose in XQuery.<br />
However, some alternatives exist in order to make conditional code more compact:<br />
<br />
* The [[XQuery 3.0#Simple Map Operator|Simple Map Operator]] can be used to trigger an action if a value has a single item. The following two expressions are equivalent:<br />
<br />
<pre class="brush:xquery"><br />
let $s := "X" return (<br />
(: OLD :) if(count($s) = 1) then 'OK' else (),<br />
(: NEW :) $s ! 'OK'<br />
)<br />
</pre><br />
<br />
In some cases, also the first solution can be written more compact. If we know that our input will always have 0-1 items, we can write <code>if(exists($s))</code>. If our input will never be an empty string, a zero, etc, it’s sufficient to write <code>if($s)</code>.<br />
<br />
* If you want to choose the first non-empty item from two arguments, we can use the position predicate:<br />
<br />
<pre class="brush:xquery"><br />
let $s := "X" return (<br />
(: OLD :) if(exists($s)) then $s else 'default',<br />
(: NEW :) ($s, 'default')[1]<br />
)<br />
</pre><br />
<br />
Note that this only works if both of your inputs have zero or one items.<br />
<br />
== Computed Elements ==<br />
Returns dynamically named elements:<br />
<pre class="brush:xquery"><br />
let $root := "element"<br />
let $value := "hi"<br />
let $contents := <foo>Bar!</foo><br />
return element { $root } {<br />
attribute { "about" } { $value }, $contents<br />
}<br />
</pre><br />
<br />
The result is an XML fragment with <code>&lt;element&gt;</code> as root node:<br />
<pre class="brush:xml"><br />
<element about="hi"><br />
<foo>Bar!</foo><br />
</element><br />
</pre><br />
<br />
== Transform List to Tree ==<br />
This snippet transform a ''flat'' list of elements with <code>parentId</code>-references to a nested list.<br />
<br />
<pre class="brush:xquery"><br />
declare function local:link($entries as node()*, $id as xs:string) {<br />
let $entry := $entries[@id eq $id],<br />
$children := $entries[@parentId eq $id]<br />
return element entry {<br />
$entry/@*,<br />
for $child in $children<br />
return local:link($entries, $child/@id)<br />
}<br />
};<br />
<br />
let $entries :=<br />
<entries><br />
<entry id="entry1" /><br />
<entry id="entry2" parentId="entry1" /><br />
<entry id="entry3" parentId="entry1" /><br />
<entry id="entry4" parentId="entry2" /><br />
<entry id="entry5" parentId="entry2" /><br />
<entry id="entry6" parentId="entry3" /><br />
<entry id="entry7" parentId="entry3" /><br />
</entries><br />
return local:link($entries/entry, 'entry1')<br />
</pre><br />
results in<br />
<pre class="brush:xml"><br />
<entry id="entry1"><br />
<entry id="entry2" parentId="entry1"><br />
<entry id="entry4" parentId="entry2"/><br />
<entry id="entry5" parentId="entry2"/><br />
</entry><br />
<entry id="entry3" parentId="entry1"><br />
<entry id="entry6" parentId="entry3"/><br />
<entry id="entry7" parentId="entry3"/><br />
</entry><br />
</entry><br />
</pre><br />
<br />
== IP-Converter ==<br />
<br />
This snippet converts an IP address to its numeric representation:<br />
<br />
<pre class="brush:xquery"><br />
let $ip := '134.34.226.65'<br />
return fold-left(<br />
tokenize($ip, '\.')!xs:integer(.),<br />
0,<br />
function($n, $d) { 256 * $n + $d }<br />
)<br />
</pre><br />
results in<br />
<pre class="brush:xml"><br />
2250433089<br />
</pre><br />
<br />
== Count number of files ==<br />
<br />
This snippets returns the number of JPG files in a directory and its sub-directories:<br />
<br />
<pre class="brush:xquery"><br />
basex "count(file:list('.',true(),'*.jpg'))"</pre><br />
<br />
The Linux equivalent is<br />
<br />
<pre class="brush:xml"><br />
find . | grep \.jpg$ | wc -l<br />
</pre></div>Andy Bunce