Difference between revisions of "XQuery Recipes"

From BaseX Documentation
Jump to navigation Jump to search
(3 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
This page contains code snippets that mainly originate from our [https://mailman.uni-konstanz.de/mailman/listinfo/basex-talk basex-talk] mailing list.
 
This page contains code snippets that mainly originate from our [https://mailman.uni-konstanz.de/mailman/listinfo/basex-talk basex-talk] mailing list.
  
== Compact XQuery ==
+
== Compact Notations ==
  
 
<code>if</code>/<code>not</code>/<code>else</code> constructs can look pretty verbose in XQuery.
 
<code>if</code>/<code>not</code>/<code>else</code> constructs can look pretty verbose in XQuery.
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">
+
<syntaxhighlight 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'
 
)
 
)
</pre>
+
</syntaxhighlight>
  
 
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:
  
<pre class="brush:xquery">
+
<syntaxhighlight 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]
 
)
 
)
</pre>
+
</syntaxhighlight>
  
 
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:
<pre class="brush:xquery">
+
<syntaxhighlight 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
 
}
 
}
</pre>
+
</syntaxhighlight>
  
 
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">
+
<syntaxhighlight lang="xml">
 
<element about="hi">
 
<element about="hi">
 
   <foo>Bar!</foo>
 
   <foo>Bar!</foo>
 
</element>
 
</element>
</pre>
+
</syntaxhighlight>
  
 
== 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.
  
<pre class="brush:xquery">
+
<syntaxhighlight 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')
</pre>
+
</syntaxhighlight>
 
results in
 
results in
<pre class="brush:xml">
+
<syntaxhighlight 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>
</pre>
+
</syntaxhighlight>
  
 
== 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:
  
<pre class="brush:xquery">
+
<syntaxhighlight 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>
+
</syntaxhighlight>
 
results in
 
results in
<pre class="brush:xml">
+
<syntaxhighlight lang="xml">
 
2250433089
 
2250433089
</pre>
+
</syntaxhighlight>
  
 
== 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 sub-directories:
 
This snippets returns the number of JPG files in a directory and its sub-directories:
  
<pre class="brush:xquery">
+
<syntaxhighlight lang="xquery">
basex "count(file:list('.',true(),'*.jpg'))"</pre>
+
basex "count(file:list('.',true(),'*.jpg'))"</syntaxhighlight>
  
 
The Linux equivalent is
 
The Linux equivalent is
  
<pre class="brush:xml">
+
<syntaxhighlight lang="xml">
 
find . | grep \.jpg$ | wc -l
 
find . | grep \.jpg$ | wc -l
</pre>
+
</syntaxhighlight>
 
 
[[Category:XQuery]]
 

Revision as of 13:23, 27 February 2020

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

Compact Notations

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:

<syntaxhighlight lang="xquery"> let $s := "X" return (

 (: OLD :) if(count($s) = 1) then 'OK' else (),
 (: NEW :) $s ! 'OK'

) </syntaxhighlight>

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:

<syntaxhighlight lang="xquery"> let $s := "X" return (

 (: OLD :) if(exists($s)) then $s else 'default',
 (: NEW :) ($s, 'default')[1]

) </syntaxhighlight>

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

Computed Elements

Returns dynamically named elements: <syntaxhighlight lang="xquery"> let $root := "element" let $value := "hi" let $contents := <foo>Bar!</foo> return element { $root } {

 attribute { "about" } { $value }, $contents

} </syntaxhighlight>

The result is an XML fragment with <element> as root node: <syntaxhighlight lang="xml"> <element about="hi">

 <foo>Bar!</foo>

</element> </syntaxhighlight>

Transform List to Tree

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

<syntaxhighlight lang="xquery"> 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') </syntaxhighlight> results in <syntaxhighlight lang="xml"> <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> </syntaxhighlight>

IP-Converter

This snippet converts an IP address to its numeric representation:

<syntaxhighlight lang="xquery"> let $ip := '134.34.226.65' return fold-left(

  tokenize($ip, '\.')!xs:integer(.),
  0,
 function($n, $d) { 256 * $n + $d }

) </syntaxhighlight> results in <syntaxhighlight lang="xml"> 2250433089 </syntaxhighlight>

Count number of files

This snippets returns the number of JPG files in a directory and its sub-directories:

<syntaxhighlight lang="xquery"> basex "count(file:list('.',true(),'*.jpg'))"</syntaxhighlight>

The Linux equivalent is

<syntaxhighlight lang="xml"> find . | grep \.jpg$ | wc -l </syntaxhighlight>