XQuery tutorial - basics

The educational technology and digital learning wiki
Jump to navigation Jump to search

Draft

Introduction

This is a beginners tutorial for XQuery.

Prerequisites:

Recommended reading, before this:

XQuery is an XML language for querying XML that can handle the following XML document types (both single documents or collections):

files
XML databases
XML fragments in memory (e.g. DOM trees)

XQuery can express queries across all these kinds of data, whether physically stored in XML or viewed as XML via middleware. In other words, you can use it to retrieve things from files, from XML representations made from SQL databases, from native XML databases like eXist. In addition, Xquery is quite a real programming language

XQuery

Relies on the Xpath (version 2.0) language
Can generate new XML documents
XQuery 1 and 2.2 does not define updating, see XQupdate (XML Query Updating)

Standards:

http://www.w3.org/TR/xquery/ (query, stable)
http://www.w3.org/TR/xqupdate/ (updates, recent)
Introductory examples

Find all nodes with path //topic/title

(returns all fragments <topic><title>xxxx </title></topic> from anywhere in the tree

for $t in //topic/title
   return $t 

Find all nodes of //topic/title in "catalog.xml"

for $t in document("catalog.xml")//topic/title
   return $t 

same, but via HTTP

for $t in document("http://tecfa.unige.ch/proj/seed/catalog/net/catalog.xml")//topic/title
   return $t 

Result

<title>TECFA Seed Catalog</title>
<title>Introduction</title>
<title>Conceptual and technical framework</title>
<title>The socio-constructivist  .... etc.
Use contexts
You need an XQuery processor
included in some command line/library products like “saxon”
included in XML databases.
included in an XML editor
included in some programming languages

Same principle as for SQL

From the command line
With an administration tool (Web or local)
Trough an other web application)
Basic XQuery
The query expression

Recall: XQuery uses XPath elements

position in a tree
ex: returns all nodes <card-propvalue> under <c3mssoft-desc> ...
//c3msbrick//c3mssoft-desc//card-propvalue
comparison
ex: returns all nodes with this id
//c3msbrick//c3mssoft[@id="epbl"]
functions
ex: only returns the content of a node
//c3msbrick/title/text()
FLWOR expressions
FLOWR = "For-Let-Where-Order-Return"
Similar to select-from-where-..-order-by of SQL

Overview:

for = iteration on a list of XML nodes
let = binding of a result to a local variable
where = selection condition
order = sorting
return = expression that will be returned

For

for $variable in expression_search
RETURN $variable

"for" associates to $variable each XML fragment found with the XPath (see The query expression)


Example:

for $t in //topic/title return $t
let
"let" assigns a value (node) to a variable
Example without let:
for $t in document("catalog09.xml")//c3msbrick//c3mssoft-desc//card-propvalue
return $t
Same example with let
for each node $t found, we bind $desc with a subnode.
for $t in document("catalog09.xml")//c3msbrick
  let $desc := $t//c3mssoft-desc//card-propvalue
return $desc
Counting, for each node $t found in the "for" loop we count the number of subnodes:
for $t in document("catalog09.xml")//c3msbrick
let $n := count($t//c3mssoft)
return <result> {$t/title/text()} owns {$n} bricks </result>
where
defines a selection condition
Same as above, but we only return results with a least 2 <c3mssoft>
for $t in document("catalog09.xml")//c3msbrick
  let $n := count($t//c3mssoft)
  where ($n > 1)
return <result> {$t/title/text()} owns {$n} bricks </result>
order
Can sort results
Alphabetic sorting:
for $t in //topic/title order by $t return $t
Alphabetic sorting
for $t in document("catalog09.xml")//c3msbrick
let $n := count($t//c3mssoft)
where ($n > 1)
order by $n
return <result> {$t/title/text()} owns {$n} bricks </result>
Slightly more complex return clause, we also include <titles> of <c3msbricks>:
for $t in document("catalog09.xml")//c3msbrick
let $brick_softs := $t//c3mssoft
let $n := count($brick_softs)
where ($n > 0)
order by $n
return <result> 
      For {$t/title/text()} we found {$n} softwares: 
         {$brick_softs//title} 
      </result>
return builds the expression to return
Warning: Each iteration must return a fragment, i.e. a single node (and not a collection!)

Good:

for $t in document("catalog09.xml")//c3msbrick
let $n := count($t//c3mssoft)
return <result> 
       {$t/title/text()} owns {$n} bricks 
       </result>

Bad:

for $t in document("catalog09.xml")//c3msbrick
let $n := count($t//c3mssoft)
return $t/title/text() owns $n bricks 
Building XML fragments
Result of an xquery usually should lead to a single node (not a list)
Multi-fragment version (collection)

Consider the following expression

for $t in //c3msbrick/title
   return $t

It will return a list (a collection)

1    <title class ="- topic/title " > TECFA Seed Catalog </ title >
2    <title class ="- topic/title " > Introduction </ title >
3    <title class ="- topic/title " > Conceptual and technical framework </ title >
4    <title class ="- topic/title " > The socio-constructivist approach </ title >
....
This sort of list is not well-formed XML, and can not be displayed in a browser for example.
... but this is not a problem if is dealt with by some program (e.g. a php script querying a DOM tree)
Version single fragment

The following expression:

 <result> 
  { for $t in //topic/title/text()
  return <titre>{$t}</titre> }
 </result>

returns:

 <result  >
 <titre > TECFA Seed Catalog </ titre >
 <titre > Introduction </ titre >
 <titre > Conceptual and technical framework </ titre >
 <titre > The socio-constructivist approach </ titre > 
 ....
 </result>
We replaced "title" tags by "titre" tags (just to make this a bit more complicated)
All expression within { ...} are evaluated
but all <tags> are copied as is ...
For within for
you may have loops within loops...
 <result>
 <title>List of C3MSBricks and associated Software</title>
 { for $t in document("catalog09.xml")//c3msbrick
   let $brick_softs := $t//c3mssoft
   let $n := count($brick_softs)
   where ($n > 0)
   order by $n descending
   return 
     <brick> Pour {$t/title/text()} on a les {$n} modules suivants:
        { for $soft in $brick_softs
          return <soft> {$soft//title/text()}</soft>
        }
     </brick>
 }
 </result>
Each FLWOR expression is within { ... }
The "return" clause of the outer loop includes a loop that will deal with
$brick_softs contains a collection of $softs from which we extract titles
We also sort the results

Result:

 <result  >
  <title > List of C3MSBricks and associated Software </ title >
  <brick > Gallery owns les 5 bricks suivants:
    <soft > PhotoShare </ soft >
    <soft > Photoshare combined with PageSetter </ soft >
    <soft > My_eGallery </ soft >
    <soft > Coppermine </ soft >
    <soft > Gallery </ soft >
  </ brick >
 <brick > User statistics owns les 5 bricks suivants:
    <soft > commArt </ soft >
    <soft > pncUserPoints </ soft >
    <soft > pncSimpleStats </ soft >
    <soft > Statistics module </ soft >
    <soft > NS-User_Points </ soft >
 </ brick > 
 .....
 </result>

Links

Software and standards

See the XQuery article.

XQuery Tutorials

XQuery Web sites