Счетчики XQuery внутри for

#xml #xquery #counter

#xml #xquery #счетчик

Вопрос:

Допустим, у меня есть приведенный ниже код XQuery:

    for $y in doc("file.xml")/A/B

        for $x in $y/C where $x/constraint1 != "-" and $x/constraint2 > 2.00
            do stuff 
  

Могу ли я использовать счетчик, чтобы подсчитать, сколько мой код введет во второй цикл for?
Я попробовал это:

    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
  

но я получил ошибки компиляции. Мне также нужно суммировать некоторые ограничения, подобные этому:

    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
  

но, конечно, это тоже не сработало :(.

Любые предложения будут высоко оценены. Кроме того, можете ли вы предложить хорошую книгу / учебник / сайт для выполнения подобных действий?

Ответ №1:

Вам это не нужно очень часто, но если вам действительно нужна переменная counter внутри for выражения XQuery position() (аналогично xsl:for-each в at ), вы можете использовать в — переменную

 for $x at $pos in //item return
  <item position="{$pos}" value="{string($x)}"/>
  

Ответ №2:

Я не думаю, что вы поняли основы декларативной парадигмы.

Общее количество и сумма будут:

 let $items := doc('file.xml')/A/B/C[constraint1 != '-' and constraint2 > 2.13]
return ('Count:', count($items), 'Sum:', sum($items/constraint2))
  

Частичное количество и сумма будут:

 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))
  

Ответ №3:

Для отображения счетчика в цикле лучшим и более простым способом является добавление в $pos в вашем цикле for. $pos будет работать как счетчик.

Фрагмент кода :

 {for $artist **at $pos** in (/ns:Entertainment/ns:Artists/ns:Name)

  return
      <tr><td>{$pos}amp;nbsp;amp;nbsp;
    {$artist}</td></tr>

}
  

Вывод:

 1   Artist

2   Artist 

3   Artist 

4   Artist

5   Artist

6   Artist
  

Ответ №4:

Вот другое решение, если вы не хотите подсчитывать или действовать с каждым элементом коллекции, но вы хотите подсчитывать / действовать только в том случае, если применяется определенное условие. В этом случае вы могли бы вспомнить парадигму функционального программирования XQuery и реализовать этот подсчет / действие с помощью рекурсивных вызовов функций:

 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
};
  

Более простым способом было бы использование соответствующего выражения XPath:

 for $element at $count in $collection[xyz = $condition]
return
    (: call your user-defined function :)
  

или даже

 myFunction($collection[xyz = $condition])
  

Рекурсивное решение может оказаться весьма полезным, если вы хотите реализовать что-то более сложное с помощью XQuery…