在XQuery中更新计数器

在XQuery中更新计数器,xquery,marklogic,Xquery,Marklogic,我想在xquery中创建一个计数器。我最初的尝试如下所示: 让$count:=0 对于$collection中的$prod 让$count:=$count+1 返回 {$count} 预期结果: 1 2. 3. 实际结果: 1 1. 1. $count变量未能更新或被重置。为什么不能重新分配现有变量?获得所需结果的更好方法是什么?不可变变量 XQuery是一个包含其他不可变变量的函数,因此您不能更改变量的值。另一方面,您可以使用功能强大的函数集合,这解决了许多日常编程问题 let $cou

我想在xquery中创建一个计数器。我最初的尝试如下所示:

让$count:=0
对于$collection中的$prod
让$count:=$count+1
返回
{$count}
预期结果:

1
2.
3.
实际结果:

1
1.
1.
$count
变量未能更新或被重置。为什么不能重新分配现有变量?获得所需结果的更好方法是什么?

不可变变量 XQuery是一个包含其他不可变变量的函数,因此您不能更改变量的值。另一方面,您可以使用功能强大的函数集合,这解决了许多日常编程问题

let $count := 0
for $prod in $collection]
  let $count := $count + 1
return 
<counter>{$count }</counter>
解决方案 要获取
$collection
中的元素总数,只需使用

return count($collection)

对于XQuery函数列表,您可以查看,其中既包含XQuery函数列表,也包含一些其他可以作为模块包含的有用函数。

尝试使用'at'

在$collection中$d在$p处
返回
元素计数器{$p}
这将为您提供每个“$d”的位置。如果要将其与
order by
子句一起使用,这将不起作用,因为位置基于初始顺序,而不是排序结果。为了克服这个问题,只需将FLWOR表达式的排序结果保存在一个变量中,并在第二个FLWOR中使用
at
子句,该FLWOR仅迭代第一个排序结果

let$sortResult:=对于$collection中的$item
按$item/id订购
退货$item
对于$sortResult中$position的$sortItem
返回。。。
正如@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)
声明函数本地:循环($seq,$count){
如果(空($seq)),则()
其他的
设$prod:=$seq[1],
$count:=$count+1
返回(
{$count},
本地:循环($seq[position()>1],$count)
)
};
本地:循环($collection,0)
这完全符合您对示例的预期

在XQuery 3.0中,甚至在标准库中定义了此函数的更通用版本:


也就是说,在您的示例中,您肯定应该在$count处使用
,如@tohuwawohu所示。

以上所有解决方案都是有效的,但我想指出的是,您可以使用XQuery脚本扩展来设置变量值:

variable $count := 0;

for $prod in (1 to 10)
return {
  $count := $count + 1;
  <counter>{$count}</counter>
}
变量$count:=0;
对于$prod in(1到10)
返回{
$count:=$count+1;
{$count}
}

您可以在特定于MarkLogic的

上尝试此示例,也可以使用
xdmp:set
。但这打破了函数式语言的假设,所以要谨慎使用


以现实世界代码中的
xdmp:set
为例,搜索解析器可能会有所帮助。

我想您正在寻找类似以下内容:

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>
为$x英寸(1到10)
返回
{$x}
输出:

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>
1
2.
3.
4.
5.
6.
7.
8.
9
10

使用
xdmp:set
而不是下面的查询

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

XQuery脚本是一些XQuery实现提供的一个扩展。如果您希望同时执行更新和返回元素(例如web服务),则这一功能特别好,但会阻止许多可能的优化。您应该尽可能坚持基本XQuery。实时示例已过期(404):(根据@JensErat的评论,这至少与
BaseX
有关,但这是如何实现的呢?我不确定您的示例是否运行,或者,至少我在运行它时遇到了问题。您能详细说明一下吗?