XML.com: XML From the Inside Out
oreilly.comSafari Bookshelf.Conferences.

advertisement

Comparing XSLT and XQuery
by J. David Eisenberg | Pages: 1, 2, 3, 4

Intermission

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.

XSLTXQuery
<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
<xsl:template match="p">
  <!-- template body -->
</xsl:template>
invoked by:
<xsl:apply-templates
   select="XPath/to/p"/>
declare function
local:process-p( $pList as element()* )
{
   for $p in $pList
   (: function body :)
}
with a call:
local:process-p( XPath/to/p )
<xsl:call-template name="action">
   <xsl:with-param name="p1"
     select="value"/>
</xsl:call-template>
let $p1 := value
return local:action($p1)
<xsl:variable name="x"
   select="value"/>
let $x := value
position() outside a predicate for $item at $pos in $sequence
<xsl:if>
No equivalent;
all if expressions
must have an else.
<xsl:choose>
  <xsl:when test="cond 1">
     <!-- value 1 -->
  <xsl:when>
  <xsl:when test="cond 2">
     <!-- value 2 -->
  </xsl:when>
  <xsl:otherwise>
     <!-- value 3 -->
  </xsl:otherwise>
if (cond 1)
   (: value 1 :)
else if (cond 2)
   (: value 2 :)
else
   (: value 3 :)
“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">  note 1
        <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()
                    &lt; $perPage]" mode="display"> note 2
              <xsl:with-param name="start" select="$start"/>
                </xsl:apply-templates>
        </table>
        </body>
        </html>
    </redirect:write>
</xsl:template>
  1. Everything between this tag and the closing </redirect:write> will be output to the file named in $filename.
  2. This ugly expression works out to the current animal and all the remaining ones on the page. It needs a mode because 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 note 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( note 2
   $animalList[position() >= $start and position() <= $end],
                 $start
                )
            }
            </table>
            </body>
            </html>
        
    let
        $outputFilename:=
            x:serialize( $htmlPage, note 3
                <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
    (
        ""
    )
};
  1. In this function, we are using multiple let clauses rather than a series of variables separated by commas; it makes the code clearer to read.
  2. We can’t use the same XPath expression that we used in the XSLT to handle the individual animals. In XSLT, makeSubfile was 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.
  3. Qizx/open’s x:serialize function 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 :) ""}

Pages: 1, 2, 3, 4

Next Pagearrow