Comparing XSLT and XQuery
by J. David Eisenberg
|
Pages: 1, 2, 3, 4
Before proceeding to the extensions for XSLT and XQuery, let’s pause for a brief summary that will help you translate from XSLT to XQuery.
| XSLT | XQuery |
|---|---|
<xsl:param name="x" select="10"/>(global parameter) |
declare variable $x as xs:integer := 10; |
Parameters to <xsl:output/> |
Command line parameters to Qizx/open |
invoked by:
|
with a call:
|
|
|
|
|
position() outside a predicate |
for $item at $pos in $sequence |
|
No equivalent; all if
expressions must have an else. |
|
|
| “Counting loops” implemented by recursion | for $i in 1 to n |
Built-in Extensions
We are now in a position to make the subfiles that display the information about
each group of pigs. Using Xalan, we must add a namespace to the
xmlns:redirect="org.apache.xalan.xslt.extensions.Redirect"
to the root <xsl:stylesheet> element. The template
that makes the subfile follows. To save space, we do not show the code
that shows the next/previous page links at the bottom of each page.
<xsl:template name="makeSubfile">
<xsl:param name="start"/>
<xsl:param name="end"/>
<xsl:param name="filename"/>
<!-- calculate this once, for use in next/back links -->
<xsl:variable name="currentPage"
select="(($start - 1) div $perPage) + 1"/>
<redirect:write select="$filename">
<html>
<head>
<link rel="stylesheet" type="text/css" href="bdr.css" />
<title>Animals Page <xsl:value-of select="$currentPage"/>
</title>
</head>
<body>
<div align="center">
<h1>Animals <xsl:value-of select="$start"/> -
<xsl:value-of
select="$end"/></h1>
</div>
<table border="0">
<xsl:apply-templates select="self::animal |
following-sibling::animal[position()
< $perPage]" mode="display">
<xsl:with-param name="start" select="$start"/>
</xsl:apply-templates>
</table>
</body>
</html>
</redirect:write>
</xsl:template>
- Everything between this tag and the closing
</redirect:write>will be output to the file named in$filename. - This ugly expression works out to the current animal and all the
remaining ones on the page. It needs a
modebecause it is processing the<animal>elements again, and the mode tells XSLT which template to invoke.
Now, the equivalent XQuery. Our strategy is to create the output
page in a variable, and then use Qizx/open’s
x:serialize extension function to direct it to a file.
declare function local:
make-subfile( $animalList as element()*,
$start as xs:integer,
$end as xs:integer,
$filename as xs:string) as xs:string
{
let
$currentPage := (($start - 1) div $perPage) + 1
let
$htmlPage :=
<html>
<head>
<link rel="stylesheet" type="text/css" href="bdr.css" />
<title>Animals Page {$currentPage}</title>
</head>
<body>
<div align="center">
<h1>Animals {$start} - {$end}</h1>
</div>
<table border="0">
{
local:display-animals(
$animalList[position() >= $start and position() <= $end],
$start
)
}
</table>
</body>
</html>
let
$outputFilename:=
x:serialize( $htmlPage,
<options output="animals{$currentPage}.html"
indent="yes"
omit-xml-declaration="yes"
doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
doctype-system=
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/>)
return
(
""
)
};
-
In this function, we are using multiple
letclauses rather than a series of variables separated by commas; it makes the code clearer to read. -
We can’t use the same XPath expression that we used in the
XSLT to handle the individual animals. In XSLT,
makeSubfilewas called in the context of an<animal>element. XQuery does not automatically pass the context on to called functions, which is why we must pass the entire$animalList. -
Qizx/open’s
x:serializefunction takes two arguments. The first is an XML tree you want serialized. The second is an element patterned along the lines of XSLT’s<xsl:output>element.
A Comment about Comments
In order to place a comment into XQuery, you enclose it in
smiley faces (: and :), which works
fine when you are in XQuery expression mode:
let $pi := 3.14159 (: just a quick approximation :)
Unfortunately, this doesn’t work well when you are in direct element constructor mode. The first of the three following examples will simply place text into the XML tree, smiley faces and all. Enclosing the comment in braces to enter XQuery expression mode gives a syntax error because an expression in braces must yield a value. The only way to get around this is to provide the null string as the value of the expression, as shown in the third example.
<a href="#">Main Page</a> (: activate link later :)
<a href="#">Main page</a> { (: activate link later :) }
<a href="#">Main page</a> { (: activate link later :) ""}