Difference between revisions of "XQuery Recipes"

From BaseX Documentation
Jump to navigation Jump to search
m (Text replace - "\[\[Category:XQuery\]\]" to "")
m (Text replacement - "syntaxhighlight" to "pre")
 
(5 intermediate revisions by 2 users 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:
  
<pre class="brush: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 (),
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:
  
<pre class="brush: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',
Line 30: Line 30:
 
== Computed Elements ==
 
== Computed Elements ==
 
Returns dynamically named elements:
 
Returns dynamically named elements:
<pre class="brush:xquery">
+
<pre lang='xquery'>
 
let $root := "element"
 
let $root := "element"
 
let $value := "hi"
 
let $value := "hi"
Line 40: Line 40:
  
 
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:
<pre class="brush:xml">
+
<pre lang="xml">
 
<element about="hi">
 
<element about="hi">
 
   <foo>Bar!</foo>
 
   <foo>Bar!</foo>
Line 49: Line 49:
 
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.
  
<pre class="brush: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 73: Line 73:
 
</pre>
 
</pre>
 
results in
 
results in
<pre class="brush:xml">
+
<pre lang="xml">
 
<entry id="entry1">
 
<entry id="entry1">
 
   <entry id="entry2" parentId="entry1">
 
   <entry id="entry2" parentId="entry1">
Line 90: Line 90:
 
This snippet converts an IP address to its numeric representation:
 
This snippet converts an IP address to its numeric representation:
  
<pre class="brush:xquery">
+
<pre lang='xquery'>
 
let $ip := '134.34.226.65'
 
let $ip := '134.34.226.65'
 
return fold-left(
 
return fold-left(
function($n, $d) { 256 * $n + $d },
+
  tokenize($ip, '\.')!xs:integer(.),
0,
+
  0,
map(xs:integer#1, tokenize($ip, '\.'))
+
  function($n, $d) { 256 * $n + $d }
 
)
 
)
 
</pre>
 
</pre>
 
results in
 
results in
<pre class="brush:xml">
+
<pre lang="xml">
 
2250433089
 
2250433089
 
</pre>
 
</pre>
Line 105: Line 105:
 
== Count number of files ==
 
== Count number of files ==
  
This snippets returns the number of JPG files in a directory and its sub-directories:
+
This snippets returns the number of JPG files in a directory and its subdirectories:
  
<pre class="brush:xquery">
+
<pre lang='xquery'>
 
basex "count(file:list('.',true(),'*.jpg'))"</pre>
 
basex "count(file:list('.',true(),'*.jpg'))"</pre>
  
 
The Linux equivalent is
 
The Linux equivalent is
  
<pre class="brush:xml">
+
<pre lang="xml">
 
find . | grep \.jpg$ | wc -l
 
find . | grep \.jpg$ | wc -l
 
</pre>
 
</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