Tutorial on XQuery

advertisement
1
XQuery
http://www.w3.org/TR/xquery/
Roger L. Costello
16 June 2010
2
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/
3
XQuery Mailing List
• There is a world-wide XQuery mailing list,
talk@x-query.com
• Here's the web page where you can
subscribe:
http://www.x-query.com/mailman/listinfo/talk
4
Usage
XQuery
Processor
FitnessCenter.xml
FitnessCenter.xq
Note: The file extension may be .xq or .xquery
HTML, XML, text
5
XQuery Processor: SAXON
• SAXON is both an XSLT processor as well
as an XQuery processor.
• I created a DOS batch file to enable you to
invoke the SAXON XQuery processor. In
the examples folders you will find:
run-saxon.bat Here's how to use it:
run-saxon FitnessCenter.xml FitnessCenter.xq FitnessCenter.html
6
Execute XQueries in
Oxygen XML
• Open Oxygen.
• Drag and drop an XQuery file into Oxygen.
• Click on the wrench icon:
Click on this wrench icon
7
Execute XQuery in
Oxygen XML (cont.)
1. Choose XQuery transformation
2. Click on New
8
Execute XQuery in
Oxygen XML (cont.)
1. Select the XML file.
2. Click on OK
9
Execute XQuery in
Oxygen XML (cont.)
Click on OK
10
1. Click on this
2. Results are shown here
11
XQuery = XPath 2.0 + more
XQuery
XPath 2.0
XPath 1.0
XQuery is a superset
of XPath 2.0, which is a
superset of XPath 1.0
12
Query this XML
We will use this XML <?xml version="1.0"?>
document throughout <FitnessCenter>
<Member level="platinum">
the tutorial, so spend a
<Name>Jeff</Name>
minute or two
<FavoriteColor>lightgrey</FavoriteColor>
familiarizing yourself
</Member>
with it.
<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
XPath can't create
elements and attributes,
XQuery can!
• XPath allows you to select nodes, compare
nodes, and perform operations on nodes.
But it doesn't allow you to create nodes,
e.g., you can't have an XPath expression
that creates <Name>Linda</Name>
• With XQuery you can create nodes.
15
Select each member's name and
wrap each name in a list item,
<li>, element:
<ul>{for $i in //Member return <li>{$i/Name/text()}</li>}</ul>
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
Note the curly braces
within curly braces
<ul>{for $i in //Member return <li>{$i/Name/text()}</li>}</ul>
18
Rule for using
curly braces
<ul>{for $i in //Member return <li>{$i/Name/text()}</li>}</ul>
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!
for $i in //Member return $i/Name/text()
Output:
JeffDavidRoger
see example02
20
Structure of an
XQuery Document
Prolog
(optional)
Body
(required)
21
Structure of the XQuery Body
• The XQuery body is a single expression,
but that expression can consist of a
sequence of one or more expressions that
are separated by commas.
expression
,
22
XQuery embedded in HTML
<?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>
<html>
<head>
<title>Member Names</title>
</head>
<body>
<h1>Member Names</h1>
<ul>
{for $i in //Member return <li>{$i/Name/text()}</li>}
</ul>
</body>
</html>
FitnessCenter.xq
FitnessCenter.xml
Evaluate the XQuery
see example01
<html>
<head>
<title>Member Names</title>
</head>
<body>
<ul>
<li>Jeff</li>
<li>David</li>
<li>Roger</li>
</ul>
</body>
</html>
23
Validate your XQuery
• You can validate your XQuery before you
execute it.
• Drag and drop the XQuery document into
Oxygen XML. Then click on the red
checkmark (in the toolbar). If your XQuery
is not a valid expression you will get an
error message.
24
Implicit vs Explicit Input
• This XQuery queries an implicit XML
document:
for $i in //Member return <li>{$i/Name/text()}</li>
• This XQuery explicitly specifies the XML
document to be queried:
for $i in doc('FitnessCenter.xml')//Member return <li>{$i/Name/text()}</li>
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>
FitnessCenter.xq
Evaluate the
XQuery
<html>
<head>…</head>
<body>
<ul>
<li>Jeff</li>
<li>David</li>
<li>Roger</li>
</ul>
</body>
</html>
<?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
Run SAXON with 2 Arguments
• I created a DOS batch file to enable you to
invoke SAXON with just the name of the
XQuery file and the name of the output file.
In the example01-a folder you will find:
run-saxon-2-args.bat Here's how to use it:
run-saxon-2-args FitnessCenter.xq FitnessCenter.html
see example01-a
27
Getting the value of an element
versus copying an element
XSLT
XQuery
<xsl:value-of select="$i/Name"/>
$i/Name/text() or
string($i/Name) or
data($i/Name)
<xsl:copy-of select="$i/Name"/>
$i/Name
Lessons Learned:
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
for $i in //Member return $i/Name/text()
Output:
JeffDavidRoger
for $i in //Member return string($i/Name)
Output:
Jeff David Roger
for $i in //Member return data($i/Name)
Output:
Jeff David Roger
for $i in //Member return $i/Name
Output:
<Name>Jeff</Name>
<Name>David</Name>
<Name>Roger</Name>
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
If you forget to wrap the
sequence in parentheses ...
for $i in //Member return "Name = ", $i/Name/text(), " FavoriteColor = ", $i/FavoriteColor/text()
Here's the error message that you get:
Error
XQuery syntax error on line 23 of
file:/C:/new-xml-course/xquery/examples/example04/FitnessCenter.xq in `...mber
return
"Name = ", $i/Name`:
Variable $i has not been declared
Failed to compile query: XQuery syntax error
Query processing failed: net.sf.saxon.xpath.StaticError: XQuery syntax error
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
XQuery embedded in 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>
FitnessCenter.xml
<?xml version="1.0"?>
<test>
<result>
{ for $i in //Member return
<Member>
<Name>{("Name = ", $i/Name/text())}</Name>
<FavoriteColor>
{("FavoriteColor = ", $i/FavoriteColor/text())}
</FavoriteColor>
</Member> }
</result>
</test>
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>
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>
Trying to iterate through <Member>
elements in the default (XHTML)
namespace!
34
Rule: put XML in a namespace
<?xml version="1.0"?>
<FitnessCenter xmlns="http://www.gym.com">
<Member level="platinum">
<Name>Jeff</Name>
<FavoriteColor>lightgrey</FavoriteColor>
</Member>
…
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
</FitnessCenter>
xmlns:gym="http://www.gym.com">
<head>
…
</head>
<body>
<h1>Fitness Center</h1>
<div id="fitness">
{
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">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
...
</html>
You will get this error about the DOCTYPE:
Error on line 1 column 0 of planets.xq:
XPST0003: XQuery syntax error in #<!D#:
Expected '--' or '[CDATA[' after '<!'
Static error(s) in query
36
Specifying HTML output
with a DOCTYPE
declare namespace saxon = "http://saxon.sf.net/";
declare option saxon:output "indent=no";
declare option saxon:output "method=html";
declare option saxon:output "doctype-public=-//W3C//DTD XHTML 1.0 Strict//EN";
declare option saxon:output "doctype-system=http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
…
</html>
Evaluate the XQuery
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
...
</html>
37
Specifying XML output
declare namespace saxon = "http://saxon.sf.net/";
declare option saxon:output "indent=no";
declare option saxon:output "method=xml";
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=____";
html, xhtml, xml, or text
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" />
for $i in //Member return <Member name="{data($i/Name)}" />
Output:
<Member name="Jeff" />
<Member name="David" />
<Member name="Roger" />
Do Lab1
see example05
41
Creating Attributes (cont.)
$i/@id returns an attribute-value pair that then gets added to
the enclosing element.
for $i in //Member return <Member>{$i/@id}</Member>
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
Create Element Value
from Attribute
• The last few slides showed how to input an
attribute and use it to create an attribute.
• Here's how to input an attribute and use it as
the value of an element:
for $i in //Member return <Member>{data($i/@id)}</Member>
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
Create Element and Attribute
for $i in //Member return <Member>{($i/@id, data($i/@level)))}</Member>
Output:
<Member id="1">platinum</Member>
<Member id="2">gold</Member>
<Member id="3">platinum</Member>
see example05
FitnessCenter.xml
FitnessCenter.xq
MemberInfo.xml
47
<?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>
<MemberInfo>
<Names>
{ for $i in //Member return $i/Name }
</Names>
<FavoriteColors>
{ for $i in //Member return $i/FavoriteColor }
</FavoriteColors>
</MemberInfo>
<?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>
Do Lab2
see example07
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>
FitnessCenter.xq ???
Members.xml
<?xml version="1.0"?>
<Members>
<platinum>
<Name>Jeff</Name>
<Name>Roger</Name>
</platinum>
<gold>
<Name>David</Name>
</gold>
</Members>
48
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
Here's what we desire
<Members>
{
for $i in distinct-values(//Member/@level) return
create an element with name string($i) and value:
{
for $j in //Member[@level eq $i] return $j/Name
}
}
</Members>
51
element {name} {value}
Here are examples of using the element keyword to
dynamically create an element:
element {"FavoriteColor"} {"blue"}
Output:
<FavoriteColor>blue</FavoriteColor>
element {"Numbers"} {1 to 10}
Output:
<Numbers>1 2 3 4 5 6 7 8 9 10</Numbers>
see example09
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
Solving the problem using a
computed element constructor
<Members>
{
for $i in distinct-values(//Member/@level) return
element {string($i)}
{
for $j in //Member[@level eq $i] return $j/Name
}
}
</Members>
The element name is computed using the value of $i.
This is called a computed element constructor.
see example10
54
Sequence values are always
separated by commas
<aircraft>
{
element altitude {12000},
element speed {160}
}
</aircraft>
Notice the comma.
It separates the two
element sequence
values.
Output:
<aircraft>
<altitude>12000</altitude>
<speed>160</speed>
</aircraft>
see example11
55
If you forget the comma ...
<aircraft>
{
element altitude {12000}
element speed {160}
}
</aircraft>
Notice there is no comma.
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
attribute {name} {value}
and
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>
Output:
<aircraft>
<altitude units="feet">12000</altitude>
<speed units="knots">160</speed>
</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.
REMINDER: SEQUENCE VALUES ARE ALWAYS
SEPARATED BY COMMAS!
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
<?xml version="1.0"?>
<MembershipLevelCosts>
<level platinum="500"/>
<level gold="400"/>
</MembershipLevelCosts>
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
Computed Attribute Constructor
<MembershipLevelCosts>
{
for $i in distinct-values(//Member/@level) return
element {"level"}
{
attribute {$i} {//Member[@level eq $i][1]/MembershipFee}
}
}
</MembershipLevelCosts>
The attribute name is computed using the value of $i.
This is called a computed attribute constructor.
Do Lab3
61
Computed Document Constructor
• This is used to create a document node:
document {value}
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
Summary of
Computed Constructors
document {value}
A document node is created.
element {name} {value}
The name of the element is computed.
attribute {name} {value}
The name of the attribute is computed.
text {value}
A text node is created.
64
Terminology
This is called a direct element constructor:
<altitude>12000</altitude>
This is called a computed element constructor:
element {"altitude"}
{
text {12000}
}
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
An XQuery Document is NOT an
XML Document
• Reserved XML characters such as "<" do not need
to be escaped (in fact, they must not be escaped).
• There is overlap between XML and XQuery:
– Every start tag must have a matching end tag.
XQuery
XML
68
Do not escape "<" or ">"
<Results>
{if (1 < 2) then "1 < 2 is TRUE" else "1 < 2 is FALSE"},
{if (1 > 2) then "1 > 2 is TRUE" else "1 > 2 is FALSE"}
</Results>
Output:
<Results>
1 < 2 is TRUE,
1 > 2 is FALSE
</Results >
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
XQuery can sort values
• XPath provides no way to sort values.
• With XQuery you can sort values.
71
for $i in expr1 order by expr2 return expr3
<html>
<body>
<ul>
{ for $i in //Member order by $i/Name/text() ascending return <li>{$i/Name/text()}</li> }
</ul>
</body>
</html>
Output:
• David
• Jeff
• Roger
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
Sort the Numbers <= 20
<?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
<html>
<body>
<ul>
{ for $i in //Number[number(text()) <= 20] order by number($i) ascending return <li>{$i/text()}</li> }
</ul>
</body>
</html>
Numbers.xq
Output:
•0
•1
•2
•5
•8
•8
• 13
• 14
• 15
• 17
• 19
see example18
73
for $i in expr1 where expr2 order by expr3 return expr4
<?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
Here's an alternative (equivalent) solution using "where expr":
<html>
<body>
<ul>
{ for $i in //Number where number($i) <= 20 order by number($i) ascending return <li>{$i/text()}</li> }
</ul>
</body>
</html>
Numbers_v2.xq
Output:
•0
•1
•2
•5
•8
•8
• 13
• 14
• 15
• 17
• 19
see example18
74
Equivalent
for $i in //Number[number(text()) <= 20] ...
for $i in //Number where number($i) <= 20 ...
75
This data
is sorted
by id
value
<?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>
Join each Member's
Name with their Age
This data
is sorted
by Name
David
Jeff
Linda
Roger
Stacey
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>
Just interested
in the first 5
Members (i.e., @id <= 5)
This data
is sorted
by Age
76
$i
<?xml version="1.0"?>
<MemberNames>
<Member id="1">
<Name>Jeff</Name>
</Member>
<Member id="2">
<Name>David</Name>
</Member>
…
</MemberNames>
$j
MemberNames.xml
<?xml version="1.0"?>
<MemberAges>
...
<Member id="1">
<Age>35</Age>
</Member>
<Member id="2">
<Age>39</Age>
</Member>
...
</MemberAges>
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>
This is an alternate
(equivalent) solution
MemberInfo_v2.xq
see example19
78
Equivalent
for $i in //Member,
$j in doc("MemberAges.xml")//Member[@id eq $i/@id]/Age
for $i in //Member
let $j := 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
Create a list of the names of all
the elements in the XML
<ul>
{
let $i := for $j in //* return name($j)
for $k in $i return <li>{$k}</li>
}
</ul>
Output:
• FitnessCenter
• Member
• Name
• Member
• Name
see example20-a
82
Create a list of distinct
FavoriteColor values
<ul>
{
let $source := doc("FitnessCenter.xml")
let $colors := $source//FavoriteColor
let $distinct := distinct-values($colors)
for $i in $distinct
return
<li>{$i}</li>
Output:
• lightgrey
• lightblue
• lightyellow
• purple
}
</ul>
see example20-b
83
Show the members for each
favorite color
Desired Output:
• Members with lightgrey as their favorite color:
• Jeff
• Sally
• Emily
• Members with lightblue as their favorite color:
• David
• George
• Members with lightyellow as their favorite color:
• Roger
• Members with purple as their favorite color:
• Linda
84
Show the members for each
favorite color
<ul>
{
let $source := doc("FitnessCenter.xml")
let $colors := $source//FavoriteColor
let $distinct := distinct-values($colors)
for $i in $distinct
return
<li>
Members with {$i} as their favorite color:
<ul>
{
let $names := $source//Member[child::FavoriteColor eq $i]/Name
for $j in $names
return
<li>{data($j)}</li>
}
</ul>
</li>
}
</ul>
see example20-c
85
Alternate solution, using "where"
<ul>
{
let $source := doc("FitnessCenter.xml")
let $colors := $source//FavoriteColor
let $distinct := distinct-values($colors)
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
Name
Jeff
David
Roger
Stacey
Linda
John
FitnessCenter.xq
Old Rate
500
450
500
400
450
500
New Rate
550
495
550
440
495
550
see example21
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).
Prolog
Version
Declaration
xquery version="1.0" encoding="UTF-8";
Variable
Declarations
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>
Function
Declarations
Namespace
Declarations
Body
89
Use Semicolons in Prolog
xquery version="1.0" encoding="UTF-8";
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>
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
declare namespace ex = "http://www.example.org";
variable declaration
declare variable $multiplicand := 3;
function declaration
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>
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
Function name must be a QName
• All user-defined function names must be
namespace qualified, i.e., the function name
must be a QName (Qualified Name).
ex:multiply
94
Don't forget the semicolons
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>
95
If you do forget ...
declare namespace ex = "http://www.example.org";
declare variable $multiplicand := 3;
declare function ex:multiply ($num)
{
$num * $multiplicand
}
forgot the semicolon here
<html>
...
</html>
Here's the error message you will get:
Error
XQuery syntax error on line 10 of Numbers.xq in '... $num * $multiplicand } <':
expected ";", found "<element>"
96
Square a number, n
declare namespace ex = "http://www.example.org";
Prolog
declare function ex:Square ($n)
{
$n * $n
};
let $result := ex:Square(4)
Body
return
$result
Do Lab5
see example23-c
97
Identity transform plus lcase
• Write an XQuery function. Pass it XML. It
converts all the element and attribute names
to lower case.
<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>
<member>
<name>Jeff</name>
<favoritecolor>lightgrey</favoritecolor>
</member>
<member>
<name>David</name>
<favoritecolor>lightblue</favoritecolor>
</member>
<member>
<name>Roger</name>
<favoritecolor>lightyellow</favoritecolor>
</member>
</fitnesscenter>
98
Here's the XQuery
declare namespace ex = "http://www.example.org";
declare function ex:identity-plus-lcase ($seq)
{
for $i in $seq
return
if ($i[self::*]) then
element {lower-case(name($i))}
{ex:identity-plus-lcase($i/child::node())}
else
text {$i}
};
ex:identity-plus-lcase(doc('FitnessCenter.xml')/*)
see example23-a
99
Oops! Forgot the attributes
• The function lost the attributes.
• The next slide shows an XQuery function
that doesn't loose the attributes.
100
Identity transform plus lcase
declare namespace ex = "http://www.example.org";
declare function ex:identity-plus-lcase ($seq)
{
for $i in $seq
return
if ($i[self::*]) then
element {lower-case(name($i))}
{
for $j in $i/@*
return
attribute {lower-case(name($j))} {data($j)},
ex:identity-plus-lcase($i/child::node())
}
else
text {$i}
};
ex:identity-plus-lcase(doc('FitnessCenter.xml')/*)
see example23-b
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
declare function m:multiply ($num)
{
$num * $m:multiplicand
};
import module namespace m = "http://www.multiplication.org" at "Multiplication-Module.xqm";
Numbers.xq
<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>
see example24
102
A Module defines a
targetNamespace
Namespace
prefix
The module's
targetNamespace
module namespace m = "http://www.multiplication.org";
declare variable $m:multiplicand := 3;
declare function m:multiply ($num)
{
$num * $m:multiplicand
};
103
Module variables
must be QNames
module namespace m = "http://www.multiplication.org";
declare variable $m:multiplicand := 3;
declare function m:multiply ($num)
{
$num * $m:multiplicand
};
Variables without a qualifier are in "no namespace."
Variable declarations that have no namespace prefix
may appear only in the XQuery Body.
104
import the module
Identify the namespace
of the module
URL location
of the module
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>
105
Namespaces must match
module namespace m = "http://www.multiplication.org";
declare variable $m:multiplicand := 3;
declare function m:multiply ($num)
{
$num * $m:multiplicand
};
The prefixes don't
have to match
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
Using Multiple Modules
module namespace m = "http://www.multiplication.org";
module namespace a = "http://www.addition.org";
declare variable $m:multiplicand := 3;
declare variable $a:add-value := 10;
declare function m:multiply ($num)
{
$num * $m:multiplicand
};
declare function a:add ($num)
{
$num + $a:add-value
};
Addition-Module.xqm
Multiplication-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
Single Module, Multiple Functions
module namespace m = "http://www.math.org";
declare variable $m:multiplicand := 3;
declare function m:multiply ($num)
{
$num * $m:multiplicand
};
declare variable $m:add-value := 10;
Rule: a file can contain
only one module.
declare function m:add ($num)
{
$num + $m:add-value
};
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
Type checking against
user-defined types
<?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>
ChapterList.xml
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.books.org"
xmlns="http://www.books.org"
elementFormDefault="qualified">
<xsd:simpleType name="Chapter">
<xsd:restriction base="xsd:string">
<xsd:pattern value="Chapter\d"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
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>
CheckChapterList.xq
see example28
111
import XML Schema
Identify the targetNamespace
of the XML Schema
URL location
of the XML Schema
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
Type checking against user-defined
types that are in no namespace
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<?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>
ChapterList.xml
<xsd:simpleType name="Chapter">
<xsd:restriction base="xsd:string">
<xsd:pattern value="Chapter\d"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
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>
Do this
CheckChapterList.xq
see example29
113
$var cast as datatype
Import an XML Schema where the elements
and types are in no namespace
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>
Type cast the value
of $i to the user-defined
type Chapter.
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
<?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>
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
let $source := doc("bookstore.xml")
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
Can XQuery produce
non-XML output?
Hi Folks,
Every time I run an XQuery, the output has an XML declaration at the top, even if the output is not XML, e.g.,
<?xml version="1.0" encoding="UTF-8"?>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
Economics in One Lesson/Henry Hazlitt/1946/0-517-54823-2/Three Rivers Press/11.00
How to Read a Book/Mortimer J. Adler/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
Is there a way to specify in the XQuery the type of output (XML, text, HTML)?
Is there a way to avoid the output having an XML declaration at the top?
/Roger
119
>Is there a way to avoid the output having an XML declaration at the top?
Yes, by engaging properties of serialization:
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 Saxon:
declare namespace saxon = "http://saxon.sf.net/";
declare option saxon:output "indent=no";
declare option saxon:output "method=text";
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'])
),
'/'
)
)
)
Do Lab7
see example31
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
Download