Xquery: Roger L. Costello 16 June 2010
Xquery: Roger L. Costello 16 June 2010
XQuery
http://www.w3.org/TR/xquery/
Prerequisites
This tutorial assumes you know XPath 1.0 and XPath 2.0 If you don't know XPath then please read my XPath tutorials at: http://www.xfront.com/xpath/
Usage
XQuery Processor
FitnessCenter.xml
FitnessCenter.xq
Note: The file extension may be .xq or .xquery
2. Click on New
2. Click on OK
Click on OK
10
1. Click on this
11
12
<Member level="gold"> <Name>David</Name> It is FitnessCenter.xml <FavoriteColor>lightblue</FavoriteColor> in the example01 </Member> folder. Please load it <Member level="platinum"> <Name>Roger</Name> into Oxygen XML. <FavoriteColor>lightyellow</FavoriteColor> </Member> </FitnessCenter>
FitnessCenter.xml
13
{ XQuery expression }
To indicate that an expression is an XQuery expression and is to be evaluated, wrap the expression within curly braces, e.g.,
<NAMES>{for $i in //Member return $i/Name/text()}</NAMES>
14
15
Select each member's name and wrap each name in a list item, <li>, element:
16
Result
<ul> <li>Jeff</li> <li>David</li> <li>Roger</li> </ul>
The XQuery created <li> elements! And the XQuery filled the <li> elements with data from the XML document.
17
18
Whenever you have an element whose contents is an XQuery expression that you want evaluated, you must wrap the expression within curly braces.
19
for $i in //Member return <li>{$i/Name/text()}</li> Output: <li>Jeff</li> <li>David</li> <li>Roger</li> for $i in //Member return <li>$i/Name/text()</li> Output: <li>$i/Name/text()</li> <li>$i/Name/text()</li> <li>$i/Name/text()</li> No curly brace, no evaluation!
20
Body (required)
21
22
FitnessCenter.xq
Evaluate the XQuery
<html> <head> <title>Member Names</title> </head> <body> <ul> <li>Jeff</li> <li>David</li> <li>Roger</li> </ul> </body> </html>
FitnessCenter.xml
see example01
23
24
25
Explicit Input
<html> <head> <title>Member Names</title> </head> <body> <h1>Member Names</h1> <ul> {for $i in doc('FitnessCenter.xml')//Member return <li>{$i/Name/text()}</li>} </ul> </body> </html>
<html> <head></head> <body> <ul> <li>Jeff</li> <li>David</li> <li>Roger</li> </ul> </body> </html>
FitnessCenter.xq
<?xml version="1.0"?> <FitnessCenter> <Member level="platinum"> <Name>Jeff</Name> <FavoriteColor>lightgrey</FavoriteColor> </Member> <Member level="gold"> <Name>David</Name> <FavoriteColor>lightblue</FavoriteColor> </Member> <Member level="platinum"> <Name>Roger</Name> <FavoriteColor>lightyellow</FavoriteColor> </Member> </FitnessCenter>
FitnessCenter.xml
26
see example01-a
27
1. In XQuery, if you want to get the value of an element either: use the text() function, or wrap the element name within the string() function, or wrap the element name within the data() function 2. In XQuery, if you want to get a copy of an element then give the element name.
28
see example03
29
Sequence of Expressions
If you have a sequence of expressions that you want evaluated then you must:
separate each expression by a comma wrap the expressions in ( )
for $i in //Member return ("Name = ", $i/Name/text(), " FavoriteColor = ", $i/FavoriteColor/text())
( expr1,
expr2,
expr3,
expr4 )
30
31 for $i in //Member return (" Name = ", $i/Name/text(), " FavoriteColor = ", $i/FavoriteColor/text())
Output:
Name = Jeff FavoriteColor = lightgrey Name = David FavoriteColor = lightblue Name = Roger FavoriteColor = lightyellow for $i in //Member return <Member>{("Name = ", $i/Name/text(), " FavoriteColor = ", $i/FavoriteColor/text())}</Member>
Output:
<Member>Name = Jeff FavoriteColor = lightgrey</Member> <Member>Name = David FavoriteColor = lightblue</Member> <Member>Name = Roger FavoriteColor = lightyellow</Member> for $i in //Member return <Member> <Name>{("Name = ", $i/Name/text())}</Name> <FavoriteColor>{("FavoriteColor = ", $i/FavoriteColor/text())}</FavoriteColor> </Member>
Output:
<Member> <Name>Name = Jeff</Name> <FavoriteColor>FavoriteColor = lightgrey</FavoriteColor> </Member> <Member> <Name>Name = David</Name> <FavoriteColor>FavoriteColor = lightblue</FavoriteColor> </Member> <Member> <Name>Name = Roger</Name> <FavoriteColor>FavoriteColor = lightyellow</FavoriteColor> /Member> see example04
32
FitnessCenter.xq
Evaluate the XQuery
<?xml version="1.0"?> <test> <result> <Member> <Name>Name = Jeff</Name> <FavoriteColor>FavoriteColor = lightgrey</FavoriteColor> </Member> <Member> <Name>Name = David</Name> <FavoriteColor>FavoriteColor = lightblue</FavoriteColor> </Member> <Member> <Name>Name = Roger</Name> <FavoriteColor> FavoriteColor = lightyellow<</FavoriteColor>
FitnessCenter.xml
33
Default Namespace
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> </head>
<body>
<h1>Fitness Center</h1> <div id="fitness"> { for $i in //Member return } </div> </body>
</html>
34
{
for $i in //gym:Member return
35
DOCTYPE Declaration
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
36
37
Actually, the default output is XML. So, you can omit these three lines.
38
Output types
declare namespace saxon = "http://saxon.sf.net/"; declare option saxon:output "indent=no"; declare option saxon:output "method=____";
39
Creating Attributes
Recall $i/Name returns a copy of the <Name> element: for $i in //Member return $i/Name Output: <Name>Jeff</Name> <Name>David</Name> <Name>Roger</Name>
When used in assigning an attribute a value, $i/Name returns the value of the <Name> element: for $i in //Member return <Member name="{$i/Name}" /> Output: <Member name="Jeff" /> <Member name="David" /> <Member name="Roger" />
40
Equivalent
for $i in //Member return <Member name="{$i/Name}" />
Output:
<Member name="Jeff" /> <Member name="David" /> <Member name="Roger" /> for $i in //Member return <Member name="{string($i/Name)}" />
Output:
<Member name="Jeff" /> <Member name="David" /> <Member name="Roger" />
Output:
<Member name="Jeff" /> <Member name="David" /> <Member name="Roger" /> see example05 Do Lab1
41
Output:
<Member id="1" /> <Member id="2" /> <Member id="3" />
42
Create 2 Attributes
for $i in //Member return <Member>{($i/@id, $i/@level)}</Member>
Output:
<Member id="1" level="platinum" /> <Member id="2" level="gold" /> <Member id="3" level="platinum" />
Remember to wrap the sequence in parentheses and separate the expressions by commas.
see example05
43
Creating 3 Attributes
{ for $i in //Member return <Member name="{$i/Name}">{($i/@id, $i/@level)}</Member> }
Output:
<Member name="Jeff" id="1" level="platinum" /> <Member name="David" id="2" level="gold" /> <Member name="Roger" id="3" level="platinum" />
see example05
44
Output:
<Member>1</Member> <Member>2</Member> <Member>3</Member>
45
Equivalent
for $i in //Member return <Member>{data($i/@id)}</Member>
Output:
<Member>1</Member> <Member>2</Member> <Member>3</Member>
for $i in //Member return <Member>{string($i/@id)}</Member>
Output:
<Member>1</Member> <Member>2</Member> <Member>3</Member>
see example05
46
Output:
<Member id="1">platinum</Member> <Member id="2">gold</Member> <Member id="3">platinum</Member>
see example05
FitnessCenter.xml
<?xml version="1.0"?> <FitnessCenter> <Member level="platinum"> <Name>Jeff</Name> <FavoriteColor>lightgrey</FavoriteColor> </Member> <Member level="gold"> <Name>David</Name> <FavoriteColor>lightblue</FavoriteColor> </Member> <Member level="platinum"> <Name>Roger</Name> <FavoriteColor>lightyellow</FavoriteColor> </Member> </FitnessCenter>
47
FitnessCenter.xq
<MemberInfo> <Names> { for $i in //Member return $i/Name } </Names> <FavoriteColors> { for $i in //Member return $i/FavoriteColor } </FavoriteColors> </MemberInfo>
MemberInfo.xml
<?xml version="1.0"?> <MemberInfo> <Names> <Name>Jeff</Name> <Name>David</Name> <Name>Roger</Name> </Names> <FavoriteColors> <FavoriteColor>lightgrey</FavoriteColor> <FavoriteColor>lightblue</FavoriteColor> <FavoriteColor>lightyellow</FavoriteColor> </FavoriteColors> </MemberInfo>
FitnessCenter.xml
<?xml version="1.0"?> <FitnessCenter> <Member level="platinum"> <Name>Jeff</Name> <FavoriteColor>lightgrey</FavoriteColor> </Member> <Member level="gold"> <Name>David</Name> <FavoriteColor>lightblue</FavoriteColor> </Member> <Member level="platinum"> <Name>Roger</Name> <FavoriteColor>lightyellow</FavoriteColor> </Member> </FitnessCenter>
48
FitnessCenter.xq ???
Members.xml
<?xml version="1.0"?> <Members> <platinum> <Name>Jeff</Name> <Name>Roger</Name> </platinum> <gold> <Name>David</Name> </gold> </Members>
49
Non-Extensible Solution
<Members> <platinum> { for $i in //Member[@level eq "platinum"] return $i/Name } </platinum> <gold> { for $i in //Member[@level eq "gold"] return $i/Name } </gold> </Members>
This XQuery document hardcodes the elements <platinum> and <gold>. Suppose that other levels were added (e.g., silver)? This solution would miss them. So, how do we make the solution more robust? see example08
50
51
52
Another Example
element {name(/*/*[1])} {/*/*[1]/*} Output: <Member> <Name>Jeff</Name> <FavoriteColor>lightgrey</FavoriteColor> </Member>
"The name of the element is the name of the first child of the root element. The value of the element is the content of the first child of the root element."
see example09
53
The element name is computed using the value of $i. This is called a computed element constructor.
see example10
54
55
Output:
Error XQuery syntax error on line 4 of file:/C:/new-xml-course/xquery/examples/example11/aircraft.xq in `...0} element speed {160`: expected "}", found "null" Failed to compile query: XQuery syntax error Query processing failed: net.sf.saxon.xpath.StaticError: XQuery syntax error
56
text {value}
Here are examples of using the attribute keyword and the text keyword to create an attribute and text node, respectively:
<aircraft> { element {"altitude"} { attribute {"units"} {"feet"}, text {12000} }, element {"speed"} { attribute {"units"} {"knots"}, text {160} } } </aircraft>
see example12
57
Use commas!
<aircraft> { element {"altitude"} { attribute {"units"} {"feet"}, text {12000} }, element {"speed"} { attribute {"units"} {"knots"}, text {160} } } </aircraft>
separate the units attribute from the text node. separate the altitude element from the speed element. separate the units attribute from the text node.
58
FitnessCenter.xml
<?xml version="1.0"?> <FitnessCenter> <Member level="platinum"> <Name>Jeff</Name> <MembershipFee>500</MembershipFee> </Member> <Member level="gold"> <Name>David</Name> <MembershipFee>400</MembershipFee> </Member> <Member level="platinum"> <Name>Roger</Name> <MembershipFee>500</MembershipFee> </Member> </FitnessCenter>
FitnessCenter.xq ???
MembershipLevelCosts.xml
59
FitnessCenter.xq
<MembershipLevelCosts> { for $i in distinct-values(//Member/@level) return element {"level"} { attribute {$i} {//Member[@level eq $i][1]/MembershipFee} } } </MembershipLevelCosts>
Output:
<MembershipLevelCosts> <level platinum="500"/> <level gold="400"/> </MembershipLevelCosts>
see example13
60
The attribute name is computed using the value of $i. This is called a computed attribute constructor.
Do Lab3
61
62
document {value}
document { element {"aircraft"} { element {"altitude"} { attribute {"units"} {"feet"}, text {12000} }, element {"speed"} { attribute {"units"} {"knots"}, text {160} } } } Output: <aircraft> <altitude units="feet">12000</altitude> <speed units="knots">160</speed> </aircraft>
see example14
63
text {value}
64
Terminology
This is called a direct element constructor: <altitude>12000</altitude>
65
Not XML
element {"altitude"} { attribute {"units"} {"feet"}, text {12000} }, element {"speed"} { attribute {"units"} {"knots"}, text {160} } Output: <altitude units="feet">12000</altitude> <speed units="knots">160</speed>
This is a perfectly fine output document. It's not an XML document. It has no root element.
This is a perfectly fine XQuery document. It's not an XML document. It has no markup. It has no root element.
see example15-a
66
No XML Declaration
Do not put an XML declaration at the top of your XQuery document.
<?xml version="1.0"?> element {"altitude"} { attribute {"units"} {"feet"}, text {12000} }, element {"speed"} { attribute {"units"} {"knots"}, text {160} }
67
XQuery
XML
68
see example15
69
Whitespace
By default whitespace that occurs around an evaluated expression is stripped.
Output:
<WhitespaceTests> <Test> hi </Test> <Test> {"hi"} </Test> <Test>   {"hi"} </Test> <Test>{1 to 10}</Test> <Test> {1 to 10} </Test> <Test> {"hi"},{"there"} </Test> <Test>{" "}</Test> <Test>{1,2,3}</Test> <Test> {1,2,3} </Test> <Test>{1}{2}{3}</Test> <Test> {1}{2}{3} </Test> </WhitespaceTests> <WhitespaceTests> <Test> hi </Test> <Test>hi</Test> <Test> hi</Test> <Test>1 2 3 4 5 6 7 8 9 10</Test> <Test>1 2 3 4 5 6 7 8 9 10</Test> <Test>hi,there</Test> <Test> </Test> <Test>1 2 3</Test> <Test>1 2 3</Test> <Test>123</Test> <Test>123</Test> </WhitespaceTests>
see example16
70
71
order by expr is used to specify how you want the data sorted. In this example I specified that I want the Members sorted using the Name field in ascending order.
see example17
72
Numbers.xq Output:
0 1 2 5 8 8 13 14 15 17 19 see example18
Numbers.xml
73
Numbers_v2.xq Output:
0 1 2 5 8 8 13 14 15 17 19 see example18
Numbers.xml
74
Equivalent
for $i in //Number[number(text()) <= 20] ...
75
<?xml version="1.0"?> <MemberNames> <Member id="1"> <Name>Jeff</Name> </Member> <Member id="2"> <Name>David</Name> </Member> <Member id="3"> <Name>Roger</Name> </Member> <Member id="4"> <Name>Stacey</Name> </Member> <Member id="5"> <Name>Linda</Name> </Member> <Member id="6"> <Name>John</Name> </Member> <Member id="7"> <Name>Diane</Name> </Member> <Member id="8"> <Name>Andy</Name> </Member> <Member id="9"> <Name>Josh</Name> </Member> <Member id="10"> <Name>Donna</Name> </Member> </MemberNames>
39 35 40 32 25
<?xml version="1.0"?> <MemberAges> <Member id="8"> <Age>19</Age> </Member> <Member id="7"> <Age>22</Age> </Member> <Member id="4"> <Age>25</Age> </Member> <Member id="10"> <Age>29</Age> </Member> <Member id="3"> <Age>32</Age> </Member> <Member id="1"> <Age>35</Age> </Member> <Member id="2"> <Age>39</Age> </Member> <Member id="5"> <Age>40</Age> </Member> <Member id="6"> <Age>44</Age> </Member> <Member id="9"> <Age>50</Age> </Member> </MemberAges>
76
<?xml version="1.0"?> <MemberNames> <Member id="1"> <Name>Jeff</Name> </Member> <Member id="2"> <Name>David</Name> </Member> </MemberNames> <?xml version="1.0"?> <MemberAges> ... <Member id="1"> <Age>35</Age> </Member> <Member id="2"> <Age>39</Age> </Member> ... </MemberAges>
$i
$j
MemberNames.xml
MemberAges.xml
<table border="1"> { for $i in //Member, $j in doc("MemberAges.xml")//Member[@id eq $i/@id]/Age where number($i/@id) <= 5 order by $i/Name/text() ascending return <tr> <td>{$i/Name/text()}</td> <td>{$j/text()}</td> </tr> } </table>
MemberInfo.xq
see example19
77
for $i in expr1 let $j := expr2 where expr3 order by expr4 return expr5
$i
<?xml version="1.0"?> <MemberNames> <Member id="1"> <Name>Jeff</Name> </Member> <Member id="2"> <Name>David</Name> </Member> </MemberNames>
$j
<?xml version="1.0"?> <MemberAges> ... <Member id="1"> <Age>35</Age> </Member> <Member id="2"> <Age>39</Age> </Member> ... </MemberAges>
<table border="1"> { for $i in //Member let $j := doc("MemberAges.xml")//Member[@id eq $i/@id]/Age where number($i/@id) <= 5 order by $i/Name/text() ascending return <tr> <td>{$i/Name/text()}</td> <td>{$j/text()}</td> </tr> } </table>
MemberInfo_v2.xq
see example19
78
Equivalent
for $i in //Member, $j in doc("MemberAges.xml")//Member[@id eq $i/@id]/Age
79
FLWOR
Pronounced: Flower for-let-where-order-return
for $i in //Member let $j := doc("MemberAges.xml")//Member[@id eq $i/@id]/Age where number($i/@id) <= 5 order by $i/Name/text() ascending return ...
Here's how FLWOR is defined: (for expr | let expr)+ (where expr)? (order by expr)? return expr
80
let $j := expr
The let clause is not a looping mechanism. It is only a variable assignment mechanism.
<table border="1"> <tr><th>$i</th><th>$j</th><th>$k</th></tr> { for $i in (1 to 3) let $j := ("red", "white", "blue") for $k in (4 to 6) return <tr> <td>{$i}</td> <td>{$j}</td> <td>{$k}</td> </tr> } </table>
Output:
$i 1 1 1 2 2 2 3 3 3 red red red red red red red red red $j white blue white blue white blue white blue white blue white blue white blue white blue white blue $k 4 5 6 4 5 6 4 5 6
Do Lab4 see example20
81
82
Output:
see example20-b
83
84
} </ul> </li>
} </ul>
see example20-c
85
for $i in $distinct return <li> Members with {$i} as their favorite color: <ul> { for $j in $source//Member where $j/child::FavoriteColor eq $i return <li>{$j/data(Name)}</li> } </ul> </li>
} </ul>
see example20-d
86
Declaring variables
The top of an XQuery document is called the Prolog. In the Prolog you can declare variables, functions, namespaces, and import other XQuery documents and schemas.
declare variable $increase := 1.1; <html> <body> <table border="1"> <tr><th>Name</th><th>Old Rate</th><th>New Rate</th></tr> { for $i in //Member return <tr> <td>{$i/Name/text()}</td> <td>{if ($i/@level eq "platinum") then 500 else if ($i/@level eq "gold") then 450 else 400}</td> <td>{if ($i/@level eq "platinum") then 500 * $increase else if ($i/@level eq "gold") then 450 * $increase else 400 * $increase}</td> </tr> } </table> </body> </html>
see example21
87
<?xml version="1.0"?> <FitnessCenter> <Member level="platinum"> <Name>Jeff</Name> </Member> <Member level="gold"> <Name>David</Name> </Member> <Member level="platinum"> <Name>Roger</Name> </Member> <Member level="silver"> <Name>Stacey</Name> </Member> <Member level="gold"> <Name>Linda</Name> </Member> <Member level="platinum"> <Name>John</Name> </Member> </FitnessCenter>
declare variable $increase := 1.1; <html> <body> <table border="1"> <tr><th>Name</th><th>Old Rate</th><th>New Rate</th></tr> { for $i in //Member return <tr> <td>{$i/Name/text()}</td> <td>{if ($i/@level eq "platinum") then 500 else if ($i/@level eq "gold") then 450 else 400}</td> <td>{if ($i/@level eq "platinum") then 500 * $increase else if ($i/@level eq "gold") then 450 * $increase else 400 * $increase}</td> </tr> } </table> </body> </html>
FitnessCenter.xml
FitnessCenter.xq
88
Prolog, Body
An XQuery document is composed of an optional Prolog followed by the Body. Up until the last slide all of our examples have just had a Body (we had no Prolog).
Version Declaration Variable Declarations
Prolog
Function Declarations
Namespace Declarations
Body
declare variable $var := expr; declare variable $var := expr; ... declare function name (params) as type { expr }; declare function name (params) as type { expr }; declare namespace prefix = "URI"; declare namespace prefix = "URI"; ... <html> </html>
89
90
Multiple Variables
This is exactly like the last example except the sequence of Members are stored in a variable:
declare variable $members := //Member; declare variable $increase := 1.1; <html> <body> <table border="1"> <tr><th>Name</th><th>Old Rate</th><th>New Rate</th></tr> { for $i in $members return <tr> <td>{$i/Name/text()}</td> <td>{if ($i/@level eq "platinum") then 500 else if ($i/@level eq "gold") then 450 else 400}</td> <td>{if ($i/@level eq "platinum") then 500 * $increase else if ($i/@level eq "gold") then 450 * $increase else 400 * $increase}</td> </tr> } </table> </body> </html>
see example22
91
Using functions
namespace declaration
variable declaration
function declaration
see example23
92
<?xml version="1.0"?> <Numbers> <Number>0</Number> <Number>8</Number> <Number>23</Number> <Number>17</Number> <Number>5</Number> <Number>19</Number> <Number>44</Number> <Number>13</Number> <Number>78</Number> <Number>21</Number> <Number>2</Number> <Number>1</Number> <Number>15</Number> <Number>67</Number> <Number>99</Number> <Number>14</Number> <Number>8</Number> <Number>33</Number> <Number>50</Number> </Numbers>
Numbers.xml
declare namespace ex = "http://www.example.org"; declare variable $multiplicand := 3; declare function ex:multiply ($num) { $num * $multiplicand }; <html> <body> <table border="1"> <tr><th>Old Value</th><th>New Value</th></tr> { for $i in //Number return <tr> <td>{data($i)}</td> <td>{ex:multiply($i)}</td> </tr> } </table> </body> </html>
Numbers.xq
see example23
93
94
95
96
Square a number, n
declare namespace ex = "http://www.example.org";
Prolog
Body
return $result
97
98
99
100
101
Modules
You can create files just containing a Prolog. These are called modules. Example: I moved the Prolog in a previous example into a separate file:
module namespace m = "http://www.multiplication.org"; declare variable $m:multiplicand := 3;
Multiplication-Module.xqm
import module namespace m = "http://www.multiplication.org" at "Multiplication-Module.xqm"; <html> <body> <table border="1"> <tr><th>Old Value</th><th>New Value</th></tr> { for $i in //Number return <tr> <td>{data($i)}</td> <td>{m:multiply($i)}</td> </tr> } </table> </body> </html>
Numbers.xq
see example24
102
module namespace m = "http://www.multiplication.org"; declare variable $m:multiplicand := 3; declare function m:multiply ($num) { $num * $m:multiplicand };
103
Variables without a qualifier are in "no namespace." Variable declarations that have no namespace prefix may appear only in the XQuery Body.
104
105
import module namespace m = "http://www.multiplication.org" at "Multiplication-Module.xqm"; <html> <body> <table border="1"> <tr><th>Old Value</th><th>New Value</th></tr> { for $i in //Number return <tr> <td>{data($i)}</td> <td>{m:multiply($i)}</td> </tr> } </table> </body> </html>
106
Filename Suffix
Use .xq as the filename suffix for XQuery files. Use .xqm as the filename suffix for XQuery Module files. By adopting this convention you will be able to quickly scan a folder and see which files are executable (the .xq files) and which are not (the .xqm files).
Do Lab6
107
Multiplication-Module.xqm
Addition-Module.xqm
import module namespace m = "http://www.multiplication.org" at "Multiplication-Module.xqm"; import module namespace a = "http://www.addition.org" at "Addition-Module.xqm"; <html> <body> <table border="1"> <tr><th>Old Value</th><th>* Value</th><th>+ Value</th></tr> { for $i in //Number return <tr> <td>{data($i)}</td> <td>{m:multiply($i)}</td> <td>{a:add($i)}</td> </tr> } </table> </body> </html>
Numbers.xq
see example25
108
Math-Module.xqm
import module namespace m = "http://www.math.org" at "Math-Module.xqm"; <html> <body> <table border="1"> <tr><th>Old Value</th><th>* Value</th><th>+ Value</th></tr> { for $i in //Number return <tr> <td>{data($i)}</td> <td>{m:multiply($i)}</td> <td>{m:add($i)}</td> </tr> } </table> </body> </html>
Numbers.xq
see example26
109
Type Checking
import module namespace m = "http://www.math.org" at "Math-Module.xqm"; declare namespace xsd = "http://www.w3.org/2001/XMLSchema"; <html> <body> <table border="1"> <tr><th>Old Value</th><th>* Value</th><th>+ Value</th></tr> { for $i in //Number return <tr> <td>{xsd:integer($i)}</td> <td>{xsd:integer(m:multiply($i))}</td> <td>{xsd:integer(m:add($i))}</td> </tr> } </table> </body> </html>
By wrapping a value within a datatype you are instructing the XQuery processor to validate that the value is of that data type.
see example27
110
UserDefinedSimpleTypes.xsd
import schema namespace bk = "http://www.books.org" at "UserDefinedSimpleTypes.xsd"; <html> <body> <table border="1"> <tr><th>Chapter</th></tr> { for $i in //li return <tr> <td>{bk:Chapter($i)}</td> </tr> } </table> </body> </html>
ChapterList.xml
CheckChapterList.xq
see example28
111
import schema namespace bk = "http://www.books.org" at "UserDefinedSimpleTypes.xsd"; <html> <body> <table border="1"> <tr><th>Chapter</th></tr> { for $i in //li return <tr> <td>{bk:Chapter($i)}</td> </tr> } </table> </body> </html>
112
<?xml version="1.0"?> <Chapters> <li>Chapter1</li> <li>Chapter2</li> <li>Chapter3</li> <li>Chapter4</li> <li>Chapter5</li> <li>Chapter6</li> <li>Chapter7</li> <li>Chapter8</li> <li>Chapter9</li> </Chapters>
UserDefinedSimpleTypes.xsd
import schema default element namespace "" at "UserDefinedSimpleTypes.xsd"; <html> <body> <table border="1"> <tr><th>Chapter</th></tr> { for $i in //li return <tr> <td>{$i cast as Chapter}</td> </tr> } </table> </body> </html>
ChapterList.xml
Do this
CheckChapterList.xq
see example29
113
114
Comments
XQuery uses the same syntax for comments as XPath 2.0
<ul>
{ let $source := doc("FitnessCenter.xml") let $colors := $source//FavoriteColor let $distinct := distinct-values($colors) for $i in $distinct (: Show distinct FavoriteColor values :) return <li>{$i}</li> } </ul>
115
Output Text
In this tutorial we have seen XQueries that created (X)HTML and XQueries that created XML. Now let's see an XQuery that creates text.
116
<?xml version="1.0" encoding="UTF-8"?> <bookstore storename="The ABC Book Store"> <book> <title>The Origin of Wealth</title> <author>Eric D. Beinhocker</author> <date>2006</date> <ISBN>1-57851-777-X</ISBN> <publisher>Harvard Business School Press</publisher> <cost currency="USD">29.95</cost> </book> </bookstore>
XML
XQuery
The ABC Book Store The Origin of Wealth/Eric D. Beinhocker/2006/1-57851-777-X/Harvard Business School Press/29.95 DOM Scripting/Jeremy Keith/2005/1-59059-533-5/friends of ed/34.99 Guns, Germs, and Steel/Jared Diamond/2005/0-393-06131-0/W. W. Norton & Company, Ltd./24.99
Text
Economics in One Lesson/Henry Hazlitt/1946/0-517-54823-2/Three Rivers Press/11.00 How to Read a Book/Mortimer J. Adler/Charles Van Doren/1940/0-671-21280-x/Simon & Schuster, Inc./15.00 Don't Make Me Think/Steve Krug/2006/0-321-34475-8/New Riders/40.00 Bulletproof Ajax/Jeremy Keith/2007/0-321-47266-7/New Riders/34.99
117
return ( string($source/bookstore/@storename), for $i in $source//book return ( "
", (: Hex A is newline :) string-join( ( string($i/title), string($i/author[1]), string($i/date), string($i/ISBN), string($i/publisher), string($i/cost[@currency='USD']) ), '/' ) ) )
see example30
118
119
>Is there a way to avoid the output having an XML declaration at the top?
http://www.w3.org/TR/2007/REC-xslt-xquery-serialization-20070123/
Not all processors support serialization, and those that do, do not support all serialization methods or properties of serialization.
The way one specifies serialization in XQuery is typically through options. Here's how to specify text output for two different products:
Using eXist: declare namespace exist = "http://exist.sourceforge.net/NS/exist"; declare option exist:serialize "method=text indent=no";
120
declare namespace saxon = "http://saxon.sf.net/"; declare option saxon:output "indent=no"; declare option saxon:output "method=text"; let $source := doc("bookstore.xml") return ( string($source/bookstore/@storename), for $i in $source//book return ( "
", string-join( ( string($i/title), string($i/author[1]), string($i/date), string($i/ISBN), string($i/publisher), string($i/cost[@currency='USD']) ), '/' ) ) )
121
XQueryX
XQueryX is an XML representation of an XQuery. It is not convenient for humans to read and write, but it is easy for programs to parse, and because XQueryX is represented in XML, standard XML tools can be used to create, interpret, or modify queries.
122
XQuery
<bib> { for $b in doc("http://bstore1.example.com/bib.xml")/bib/book where $b/publisher = "Addison-Wesley" and $b/@year > 1991 return <book year="{ $b/@year }"> { $b/title } </book> } </bib>
123
XQueryX
http://www.w3.org/TR/xqueryx/#Example1-XQueryX