Difference between revisions of "XQuery Recipes"

From BaseX Documentation
Jump to navigation Jump to search
m (Text replacement - "ub-director" to "ubdirector")
m (Text replacement - "syntaxhighlight" to "pre")
 
(2 intermediate revisions by the same user not shown)
Line 8: Line 8:
 
* 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:
 
* 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:
  
<syntaxhighlight lang="xquery">
+
<pre lang='xquery'>
 
let $s := "X" return (
 
let $s := "X" return (
 
   (: OLD :) if(count($s) = 1) then 'OK' else (),
 
   (: OLD :) if(count($s) = 1) then 'OK' else (),
 
   (: NEW :) $s ! 'OK'
 
   (: NEW :) $s ! 'OK'
 
)
 
)
</syntaxhighlight>
+
</pre>
  
 
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>.
 
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>.
Line 19: Line 19:
 
* If you want to choose the first non-empty item from two arguments, we can use the position predicate:
 
* If you want to choose the first non-empty item from two arguments, we can use the position predicate:
  
<syntaxhighlight lang="xquery">
+
<pre lang='xquery'>
 
let $s := "X" return (
 
let $s := "X" return (
 
   (: OLD :) if(exists($s)) then $s else 'default',
 
   (: OLD :) if(exists($s)) then $s else 'default',
 
   (: NEW :) ($s, 'default')[1]
 
   (: NEW :) ($s, 'default')[1]
 
)
 
)
</syntaxhighlight>
+
</pre>
  
 
Note that this only works if both of your inputs have zero or one items.
 
Note that this only works if both of your inputs have zero or one items.
Line 30: Line 30:
 
== Computed Elements ==
 
== Computed Elements ==
 
Returns dynamically named elements:
 
Returns dynamically named elements:
<syntaxhighlight lang="xquery">
+
<pre lang='xquery'>
 
let $root := "element"
 
let $root := "element"
 
let $value := "hi"
 
let $value := "hi"
Line 37: Line 37:
 
   attribute { "about" } { $value }, $contents
 
   attribute { "about" } { $value }, $contents
 
}
 
}
</syntaxhighlight>
+
</pre>
  
 
The result is an XML fragment with <code>&lt;element&gt;</code> as root node:
 
The result is an XML fragment with <code>&lt;element&gt;</code> as root node:
<syntaxhighlight lang="xml">
+
<pre lang="xml">
 
<element about="hi">
 
<element about="hi">
 
   <foo>Bar!</foo>
 
   <foo>Bar!</foo>
 
</element>
 
</element>
</syntaxhighlight>
+
</pre>
  
 
== Transform List to Tree ==
 
== Transform List to Tree ==
 
This snippet transform a ''flat'' list of elements with <code>parentId</code>-references to a nested list.
 
This snippet transform a ''flat'' list of elements with <code>parentId</code>-references to a nested list.
  
<syntaxhighlight lang="xquery">
+
<pre lang='xquery'>
 
declare function local:link($entries as node()*, $id as xs:string) {
 
declare function local:link($entries as node()*, $id as xs:string) {
 
  let $entry    := $entries[@id eq $id],
 
  let $entry    := $entries[@id eq $id],
Line 71: Line 71:
 
  </entries>
 
  </entries>
 
return local:link($entries/entry, 'entry1')
 
return local:link($entries/entry, 'entry1')
</syntaxhighlight>
+
</pre>
 
results in
 
results in
<syntaxhighlight lang="xml">
+
<pre lang="xml">
 
<entry id="entry1">
 
<entry id="entry1">
 
   <entry id="entry2" parentId="entry1">
 
   <entry id="entry2" parentId="entry1">
Line 84: Line 84:
 
   </entry>
 
   </entry>
 
</entry>
 
</entry>
</syntaxhighlight>
+
</pre>
  
 
== IP-Converter ==
 
== IP-Converter ==
Line 90: Line 90:
 
This snippet converts an IP address to its numeric representation:
 
This snippet converts an IP address to its numeric representation:
  
<syntaxhighlight lang="xquery">
+
<pre lang='xquery'>
 
let $ip := '134.34.226.65'
 
let $ip := '134.34.226.65'
 
return fold-left(
 
return fold-left(
Line 97: Line 97:
 
   function($n, $d) { 256 * $n + $d }
 
   function($n, $d) { 256 * $n + $d }
 
)
 
)
</syntaxhighlight>
+
</pre>
 
results in
 
results in
<syntaxhighlight lang="xml">
+
<pre lang="xml">
 
2250433089
 
2250433089
</syntaxhighlight>
+
</pre>
  
 
== Count number of files ==
 
== Count number of files ==
Line 107: Line 107:
 
This snippets returns the number of JPG files in a directory and its subdirectories:
 
This snippets returns the number of JPG files in a directory and its subdirectories:
  
<syntaxhighlight lang="xquery">
+
<pre lang='xquery'>
basex "count(file:list('.',true(),'*.jpg'))"</syntaxhighlight>
+
basex "count(file:list('.',true(),'*.jpg'))"</pre>
  
 
The Linux equivalent is
 
The Linux equivalent is
  
<syntaxhighlight lang="xml">
+
<pre lang="xml">
 
find . | grep \.jpg$ | wc -l
 
find . | grep \.jpg$ | wc -l
</syntaxhighlight>
+
</pre>

Latest revision as of 18:38, 1 December 2023

This page contains code snippets that mainly originate from our basex-talk mailing list.

Compact Notations[edit]

if/not/else constructs can look pretty verbose in XQuery. However, some alternatives exist in order to make conditional code more compact:

  • The Simple Map Operator can be used to trigger an action if a value has a single item. The following two expressions are equivalent:
let $s := "X" return (
  (: OLD :) if(count($s) = 1) then 'OK' else (),
  (: NEW :) $s ! 'OK'
)

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 if(exists($s)). If our input will never be an empty string, a zero, etc, it’s sufficient to write if($s).

  • If you want to choose the first non-empty item from two arguments, we can use the position predicate:
let $s := "X" return (
  (: OLD :) if(exists($s)) then $s else 'default',
  (: NEW :) ($s, 'default')[1]
)

Note that this only works if both of your inputs have zero or one items.

Computed Elements[edit]

Returns dynamically named elements:

let $root := "element"
let $value := "hi"
let $contents := <foo>Bar!</foo>
return element { $root } {
  attribute { "about" } { $value }, $contents
}

The result is an XML fragment with <element> as root node:

<element about="hi">
  <foo>Bar!</foo>
</element>

Transform List to Tree[edit]

This snippet transform a flat list of elements with parentId-references to a nested list.

declare function local:link($entries as node()*, $id as xs:string) {
 let $entry    := $entries[@id eq $id],
     $children := $entries[@parentId eq $id]
 return element entry {
   $entry/@*,
   for $child in $children
   return local:link($entries, $child/@id)
 }
};

let $entries :=
 <entries>
	  <entry id="entry1" />
	  <entry id="entry2" parentId="entry1" />
	  <entry id="entry3" parentId="entry1" />
	  <entry id="entry4" parentId="entry2" />
	  <entry id="entry5" parentId="entry2" />
	  <entry id="entry6" parentId="entry3" />
	  <entry id="entry7" parentId="entry3" />
 </entries>
return local:link($entries/entry, 'entry1')

results in

<entry id="entry1">
  <entry id="entry2" parentId="entry1">
    <entry id="entry4" parentId="entry2"/>
    <entry id="entry5" parentId="entry2"/>
  </entry>
  <entry id="entry3" parentId="entry1">
    <entry id="entry6" parentId="entry3"/>
    <entry id="entry7" parentId="entry3"/>
  </entry>
</entry>

IP-Converter[edit]

This snippet converts an IP address to its numeric representation:

let $ip := '134.34.226.65'
return fold-left(
   tokenize($ip, '\.')!xs:integer(.),
   0,
  function($n, $d) { 256 * $n + $d }
)

results in

2250433089

Count number of files[edit]

This snippets returns the number of JPG files in a directory and its subdirectories:

basex "count(file:list('.',true(),'*.jpg'))"

The Linux equivalent is

find . | grep \.jpg$ | wc -l