Introduction to XQuery

by K. Yue

1. Introduction

Resources:

Basics:

Comparisons to SQL:

  Relational DB: SQL XML DB: XQuery
Basic Unit relations collections
Records tuples or rows of the schema documents of the same schema
Schema Relational Schema XML Schema
Query Result Relations: ordered set of rows Ordered sequence of (mostly) nodes.

 

XQuery Data Types

XQuery Datatypes

Query Expressions

Functions

Prolog

Example: Variable declaration

Format: declare variable $name = expression;

declare variable $a := doc("census.xml")//person ;

Path Expressions

Example: In Editix,

Use "View > Windows > XQuery Builder" For XQ files

Use "XSLT/XQuery > Transform using an XQuery Request…"

Specify source xq file, xml file and output file. Use .xml extension. If you use .txt extension, only text node contents are output.

declare base-uri "whatever-path";
doc("bib.xml")/*

Return basically bib.xml.

doc("bib.xml")//*

Element Constructors

Example: The XQuery

<authors>
    <author>Bun Yue</author>
</authors>

returns

<authors>
    <author>Bun Yue</author>
</authors>

Example:

Using film.xml:

<films>
   <titles>
      { //film/title }
   </titles>
</films>

returns:

<?xml version="1.0" encoding="UTF-8"?>
<films>
   <titles>
      <title>ACADEMY DINOSAUR</title>
      <title>ACE GOLDFINGER</title>
      <title>ADAPTATION HOLES</title>
      ...
      <title>ZOOLANDER FICTION</title>
      <title>ZORRO ARK</title>
   </titles>
</films>
 

Example:

<films>
   { element titles
      { //film/title }
   }
</films>
 

return the same result as the previous example.

element films {
   attribute numFilms {
      count(//film)
   }
}

returns

<?xml version="1.0" encoding="UTF-8"?>
<films numFilms="1000"/>

<categories>
{   for $c in fn:distinct-values(//category/text())
   return
   <category>
      <name>{ $c }</name>
   </category>
}
</categories>

returns

<?xml version="1.0" encoding="UTF-8"?>
<categories>
   <category>
      <name>Documentary</name>
   </category>
   <category>
      <name>Horror</name>
   </category>
   <category>
      <name>Family</name>
   </category>
   <category>
      <name>Foreign</name>
   </category>
   <category>
      <name>Comedy</name>
   </category>
   <category>
      <name>Sports</name>
   </category>
   <category>
      <name>Music</name>
   </category>
   <category>
      <name>Classics</name>
   </category>
   <category>
      <name>Animation</name>
   </category>
   <category>
      <name>Action</name>
   </category>
   <category>
      <name>New</name>
   </category>
   <category>
      <name>Sci-Fi</name>
   </category>
   <category>
      <name>Drama</name>
   </category>
   <category>
      <name>Travel</name>
   </category>
   <category>
      <name>Games</name>
   </category>
   <category>
      <name>Children</name>
   </category>
</categories>

Example:

<categories>
{   for $c in fn:distinct-values(//category/text())
   return
   <category>
      <name>{ $c }</name>
      {   element numFiles
         { count(//film/category/text()=$c) }
      }
   </category>
}
</categories>


returns:

<?xml version="1.0" encoding="UTF-8"?>
<categories>
   <category>
      <name>Documentary</name>
      <numFiles>1</numFiles>
   </category>
   <category>
      <name>Horror</name>
      <numFiles>1</numFiles>
   </category>
   <category>
      <name>Family</name>
      <numFiles>1</numFiles>
   </category>
   <category>
      <name>Foreign</name>
      <numFiles>1</numFiles>
   </category>
   <category>
      <name>Comedy</name>
      <numFiles>1</numFiles>
   </category>
   <category>
      <name>Sports</name>
      <numFiles>1</numFiles>
   </category>
   <category>
      <name>Music</name>
      <numFiles>1</numFiles>
   </category>
   <category>
      <name>Classics</name>
      <numFiles>1</numFiles>
   </category>
   <category>
      <name>Animation</name>
      <numFiles>1</numFiles>
   </category>
   <category>
      <name>Action</name>
      <numFiles>1</numFiles>
   </category>
   <category>
      <name>New</name>
      <numFiles>1</numFiles>
   </category>
   <category>
      <name>Sci-Fi</name>
      <numFiles>1</numFiles>
   </category>
   <category>
      <name>Drama</name>
      <numFiles>1</numFiles>
   </category>
   <category>
      <name>Travel</name>
      <numFiles>1</numFiles>
   </category>
   <category>
      <name>Games</name>
      <numFiles>1</numFiles>
   </category>
   <category>
      <name>Children</name>
      <numFiles>1</numFiles>
   </category>
</categories>

The XQuery:

<categories>
{   for $c in fn:distinct-values(//category/text())
   return
   element { $c }
   {   attribute numFiles
         { count(//film[category/text()=$c]) }
   }
}
</categories>


returns:

<?xml version="1.0" encoding="UTF-8"?>
<categories>
   <Documentary numFiles="68"/>
   <Horror numFiles="56"/>
   <Family numFiles="69"/>
   <Foreign numFiles="73"/>
   <Comedy numFiles="58"/>
   <Sports numFiles="74"/>
   <Music numFiles="51"/>
   <Classics numFiles="57"/>
   <Animation numFiles="66"/>
   <Action numFiles="64"/>
   <New numFiles="63"/>
   <Sci-Fi numFiles="61"/>
   <Drama numFiles="62"/>
   <Travel numFiles="57"/>
   <Games numFiles="61"/>
   <Children numFiles="60"/>
</categories>
 

FLWOR expressions

From W3C:

[42]    FLWORExpr    ::=    (ForClause | LetClause)+ WhereClause? OrderByClause? "return" ExprSingle
[43]    ForClause    ::=    "for" "$" VarName TypeDeclaration? PositionalVar? "in" ExprSingle ("," "$" VarName TypeDeclaration? PositionalVar? "in" ExprSingle)*
[45]    LetClause    ::=    "let" "$" VarName TypeDeclaration? ":=" ExprSingle ("," "$" VarName TypeDeclaration? ":=" ExprSingle)*
[123]    TypeDeclaration    ::=    "as" SequenceType
[44]    PositionalVar    ::=    "at" "$" VarName
[46]    WhereClause    ::=    "where" Expr
[47]    OrderByClause    ::=    ("order" "by" | "stable" "order" "by") OrderSpecList
[48]    OrderSpecList    ::=    OrderSpec ("," OrderSpec)*
[49]    OrderSpec    ::=    ExprSingle OrderModifier
[50]    OrderModifier    ::=    ("ascending" | "descending")? (("empty" "greatest") | ("empty" "least"))? ("collation" StringLiteral)?

 

Example:

List the film categories with 60 or more films in ascending orders of category names.

<categories>
{   for $cat in fn:distinct-values(//category/text())
   let $count := count(//film[category/text()=$cat])
   where $count >= 60
   order by $cat
   return
   element { $cat }
   {   attribute numFiles
         { $count }
   }
}
</categories>


Output:

<?xml version="1.0" encoding="UTF-8"?>
<categories>
   <Action numFiles="64"/>
   <Animation numFiles="66"/>
   <Children numFiles="60"/>
   <Documentary numFiles="68"/>
   <Drama numFiles="62"/>
   <Family numFiles="69"/>
   <Foreign numFiles="73"/>
   <Games numFiles="61"/>
   <New numFiles="63"/>
   <Sci-Fi numFiles="61"/>
   <Sports numFiles="74"/>
</categories>

List ids of actors 'KILMER'.

XQuery:

element actors
{   for $aid in fn:distinct-values
      (//actor[text()[contains(.,'KILMER')]]/@id)
   return
   element actor
   {    attribute id { $aid }
   }
}

Output:

<?xml version="1.0" encoding="UTF-8"?>
<actors>
   <actor id="162"/>
   <actor id="23"/>
   <actor id="55"/>
   <actor id="45"/>
   <actor id="153"/>
</actors>
 

List names and ids of actors 'KILMER'.

XQuery:

element actors
{   for $aid in fn:distinct-values
      (//actor[text()[contains(.,'KILMER')]]/@id)
   let $aname := (//actor[@id=$aid][1]/text())[1]
   return
   element actor
   {   attribute id { $aid },
      element name { $aname }
   }
}

Output:

<?xml version="1.0" encoding="UTF-8"?>
<actors>
   <actor id="162">
      <name>OPRAH KILMER</name>
   </actor>
   <actor id="23">
      <name>SANDRA KILMER</name>
   </actor>
   <actor id="55">
      <name>FAY KILMER</name>
   </actor>
   <actor id="45">
      <name>REESE KILMER</name>
   </actor>
   <actor id="153">
      <name>MINNIE KILMER</name>
   </actor>
</actors>

List names, ids and number of films of actors 'KILMER'.

XQuery:

element actors
{   for $aid in fn:distinct-values
      (//actor[text()[contains(.,'KILMER')]]/@id)
   let $name := (//actor[@id=$aid]/text())[1],
       $n_films := count(//film[actor/@id = $aid])
   order by number($n_films) descending
   return
   element actor
   {    attribute id { $aid }, 
       element name { $name },
       element nFilms { $n_films }
   }
}

Output:

<?xml version="1.0" encoding="UTF-8"?>
<actors>
   <actor id="23">
      <name>SANDRA KILMER</name>
      <nFilms>37</nFilms>
   </actor>
   <actor id="45">
      <name>REESE KILMER</name>
      <nFilms>32</nFilms>
   </actor>
   <actor id="162">
      <name>OPRAH KILMER</name>
      <nFilms>25</nFilms>
   </actor>
   <actor id="55">
      <name>FAY KILMER</name>
      <nFilms>20</nFilms>
   </actor>
   <actor id="153">
      <name>MINNIE KILMER</name>
      <nFilms>20</nFilms>
   </actor>
</actors>