XSLT 2.0 and XPath 2.0 Programmer's Reference, 4th Edition (444 page)

BOOK: XSLT 2.0 and XPath 2.0 Programmer's Reference, 4th Edition
6Mb size Format: txt, pdf, ePub

A common mistake is to forget that
for
expressions don't set the context node. The following example is wrong (it's not an error, but it doesn't do what the writer probably intended):

(:wrong:) sum(for $i in item return @price * @qty)

The correct way of writing this is:

(:correct:) sum(for $i in item return $i/@price * $i/@qty)

Generally speaking, there is usually something amiss if the range variable is not used in the
return
expression. However, there are exceptions to this rule. For example, it's quite reasonable to write:

string-join(for $i in 1 to $n return “-”, “”)

which returns a string containing
$n
hyphens.

It's also often (but not invariably) a sign of trouble if the value of the return expression depends on the context item. But it's not actually an error: the context item inside the return expression is exactly the same as the context item for the
for
expression as a whole. So it's legal to write an expression such as:

chapter/(for $i in 1 to 10 return section[$i])

which returns the first 10 sections of each chapter.

Combining Multiple Sequences

The
for
expression allows multiple input sequences to be defined, each with its own range variable. For example, you can write:

for $c in //customer,

    $o in $c/orders,

    $ol in $o/line

return $ol/cost

The simplest way to think about this is as a nested loop. You can regard the
,
as a shorthand for writing the keywords
return for
, so the above expression is equivalent to:

for $c in //customer

return

   for $o in $c/orders

   return

      for $ol in $o/line

      return $ol/cost

Note that each of the range variables can be referenced in the expression that defines the input sequence for the next range variable.

In the example above, each iteration is rather like a step in a path expression; it selects nodes starting from the node selected in the containing loop. But it doesn't have to be this way. For example, you could equally write an expression such as:

for $c in doc(‘customers.xml’)//customer,

    $p in doc(‘products.xml’)//product [$c/orders/product-code = $p/code]

    return $c/line/cost

Other books

Sweetest Temptations by J.C. Valentine
Asylum by Kristen Selleck
Pieces of Rhys by L. D. Davis
False God of Rome by Robert Fabbri
Extreme Measures by Vince Flynn