Обновление счетчика в 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>