Reputation: 71
Let's say I have the XQuery code below:
for $y in doc("file.xml")/A/B
for $x in $y/C where $x/constraint1 != "-" and $x/constraint2 > 2.00
do stuff
Can I use a counter, to count how many my code will enter inside the second for loop? I tried this:
for $y in doc("file.xml")/A/B
let $i := 0
for $x in $y/C where $x/constraint1 != "-" and $x/constraint2 > 2.00
$i := $i + 1
but I got compile errors. I also I need to sum some constraints like this:
for $y in doc("file.xml")/A/B
let $i := 0
let $sum := 0
for $x in $y/C where $x/constraint1 != "-" and $x/constraint2 > 2.13
$i := $i + 1
$sum := $sum + $x/constraint2
but of course this didn't work either :(.
Any suggestions will be highly appreciated. Also, can you suggest a good book/tutorial/site for doing such stuff?
Upvotes: 7
Views: 19608
Reputation: 163625
You don't need it very often, but if you really do need a counter variable inside an XQuery for
expression (analogous to position()
in an xsl:for-each
) you can use an at
variable
for $x at $pos in //item return
<item position="{$pos}" value="{string($x)}"/>
Upvotes: 22
Reputation: 1
Here is another solution, if you don't want to count or act on every item of a collection, but you want to count/act only, if a certain condition applies. In that case you might remember the functional programming paradigm of XQuery and implement this counting/acting by using recursive function calls:
declare function ActIf($collection as element(*)*, $index as xs:integer, $indexMax as xs:integer, $condition as xs:string, $count as xs:integer) as xs:integer
{
if($index <= $indexMax) then
let $element := $collection[$index]
if($element/xyz/text() eq $condition) then
(: here you can call a user-defined function before continuing to the next element :)
ActIf($collection, $index + 1, $indexMax, $condition, $count + 1)
else
ActIf($collection, $index + 1, $indexMax, $condition, $count)
else (: no more items left:)
$count
};
The more easier way would be the usage of an appropriate XPath expression:
for $element at $count in $collection[xyz = $condition]
return
(: call your user-defined function :)
or even
myFunction($collection[xyz = $condition])
The recursive solution might be quite helpful, if you want to implement something more complex with XQuery...
Upvotes: 0
Reputation: 1
To Display counter in loop the best and easier way is to add at $pos in your for loop. $pos will work as a counter.
Code Snippet :
{for $artist **at $pos** in (/ns:Entertainment/ns:Artists/ns:Name)
return
<tr><td>{$pos}
{$artist}</td></tr>
}
Output:
1 Artist
2 Artist
3 Artist
4 Artist
5 Artist
6 Artist
Upvotes: 0
Reputation:
I don't think you have understood the basics of declarative paradigm.
Total count and sum would be:
let $items := doc('file.xml')/A/B/C[constraint1 != '-' and constraint2 > 2.13]
return ('Count:', count($items), 'Sum:', sum($items/constraint2))
Partial count and sum would be:
let $items := doc('file.xml')/A/B/C[constraint1 != '-' and constraint2 > 2.13]
for $pos in (1 to count($items))
return ('Count:', $pos, 'Sum:', sum($items[position() le $pos]/constraint2))
Upvotes: 1