Обновление счетчика в XQuery

Я хочу создать счетчик в xquery. Моя первоначальная попытка выглядела следующим образом:

let $count := 0
for $prod in $collection
let $count := $count + 1
return 
<counter>{$count }</counter>

Ожидаемый результат:

<counter>1</counter>
<counter>2</counter>  
<counter>3</counter>

Фактический результат:

<counter>1</counter>
<counter>1</counter>  
<counter>1</counter>

Переменная $count либо не обновляется, либо является reset. Почему я не могу переназначить существующую переменную? Что было бы лучшим способом получить желаемый результат?

Ответ 1

Попробуйте использовать 'в':

for $d at $p in $collection
return 
element counter { $p }

Это даст вам положение каждого "$ d". Если вы хотите использовать это вместе с предложением order by, это не сработает, поскольку позиция основана на начальном порядке, а не на результате сортировки. Чтобы преодолеть это, просто сохраните отсортированный результат выражения FLWOR в переменной и используйте предложение at во втором FLWOR, которое просто выполняет итерацию по первому, отсортированному результату.

let $sortResult := for $item in $collection
                   order by $item/id
                   return $item

for $sortItem at $position in $sortResult
return <item position="{$position}"> ... </item>

Ответ 2

Неизменяемые переменные

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

let $count := 0
for $prod in $collection]
  let $count := $count + 1
return 
<counter>{$count }</counter>

let $count в строке 1 определяет эту переменную во всей области видимости, которая в этом случае соответствует следующим строкам. let $count в строке 3 определяет новый $count, который 0+1, действительный во всех следующих строках внутри этого блока кода, который не определен. Поэтому вы действительно увеличиваете $count три раза на единицу, но немедленно отбрасываете результат.

BaseX 'информация о запросе показывает оптимизированную версию этого запроса, которая

for $prod in $collection
  return element { "counter" } { 1 }

Решение

Чтобы получить общее количество элементов в $collection, вы можете просто использовать

return count($collection)

Для списка функций XQuery вы можете посмотреть часть XQuery functx, которая содержит как список функций XQuery, так и некоторые другие полезные функции, которые может быть включен как модуль.

Ответ 3

Как сказал @Ranon, все значения XQuery неизменяемы, поэтому вы не можете обновить переменную. Но если вам действительно нужен обновляемый номер (не должен быть слишком часто), вы можете использовать рекурсию:

declare function local:loop($seq, $count) {
  if(empty($seq)) then ()
  else
    let $prod  := $seq[1],
        $count := $count + 1
    return (
      <count>{ $count }</count>,
      local:loop($seq[position() > 1], $count)
    )
};

local:loop($collection, 0)

Это ведет себя точно так же, как вы предполагали в своем примере.

В XQuery 3.0 более общая версия этой функции даже определена в стандартной библиотеке: fn: fold-right ($ f, $zero, $seq )

Тем не менее, в вашем примере вы обязательно должны использовать at $count, как показано @tohuwawohu.

Ответ 4

Все вышеприведенное решение верны, но я хотел бы упомянуть, что вы можете использовать расширение XQuery Scripting для установки значений переменных:

variable $count := 0;

for $prod in (1 to 10)
return {
  $count := $count + 1;
  <counter>{$count}</counter>
}

Вы можете попробовать этот пример в прямом эфире http://www.zorba-xquery.com/html/demo#twh+3sJfRpHhZR8pHhOdsmqOTvQ=

Ответ 5

Конкретно для MarkLogic вы также можете использовать xdmp:set. Но это нарушает предположения функционального языка, поэтому используйте его консервативно.

http://docs.marklogic.com/5.0doc/docapp.xqy#display.xqy?fname=http://pubs/5.0doc/apidoc/ExsltBuiltins.xml&category=Extension&function=xdmp:set

Для примера xdmp:set в коде реального мира может оказаться полезным поисковый парсер https://github.com/mblakele/xqysp/blob/master/src/xqysp.xqy.

Ответ 6

Используйте xdmp:set вместо указанного ниже запроса

let $count := 0
for $prod in (1 to 4)
return ( xdmp:set($count,number($count+1)) ,<counter>{$count }</counter> 

Ответ 7

Я думаю, вы ищете что-то вроде:

XQUERY:

for $x in (1 to 10)
return
  <counter>{$x}</counter>

ВЫВОД:

<counter>1</counter>
<counter>2</counter>
<counter>3</counter>
<counter>4</counter>
<counter>5</counter>
<counter>6</counter>
<counter>7</counter>
<counter>8</counter>
<counter>9</counter>
<counter>10</counter>