Difference between revisions of "XQuery Recipes"

From BaseX Documentation
Jump to navigation Jump to search
(9 intermediate revisions by 3 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 Notations ==
 +
 +
<code>if</code>/<code>not</code>/<code>else</code> constructs can look pretty verbose in XQuery.
 +
However, some alternatives exist in order to make conditional code more compact:
 +
 +
* 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">
 +
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 <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>.
 +
 +
* 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 ==
 
== Computed Elements ==
 
Returns dynamically named elements:
 
Returns dynamically named elements:
<pre class="brush:xquery">
+
<syntaxhighlight lang="xquery">
let $name:= "element"
+
let $root := "element"
let $class := "hi"
+
let $value := "hi"
 
let $contents := <foo>Bar!</foo>
 
let $contents := <foo>Bar!</foo>
return element { $name } {
+
return element { $root } {
   attribute { "about" } { $class }, $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 ==
 +
This snippet transform a ''flat'' list of elements with <code>parentId</code>-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
  
[[Category:XQuery]]
+
<syntaxhighlight lang="xml">
 +
find . | grep \.jpg$ | wc -l
 +
</syntaxhighlight>

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>