在XQuery中更新计数器

13

我想在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变量要么没有更新,要么被重置。为什么我不能重新分配一个已经存在的变量?有什么更好的方法来获得所需结果吗?

7个回答

22

尝试使用'at'

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

这将给出每个“$d”的位置。如果您想与order by子句一起使用,则无法正常工作,因为位置是基于初始顺序而不是排序结果的。为了解决这个问题,只需保存FLWOR表达式的排序结果到变量中,并在第二个FLWOR中使用at子句遍历第一个已排序的结果。

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

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

9

正如 @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)

话虽如此,在你的示例中,你应该像 @tohuwawohu 所示使用 at $count


6

6

不可变变量

XQuery是一种函数式编程语言,其中包含不可变变量等特性,因此您无法更改变量的值。另一方面,您可以使用强大的函数集合来解决许多日常编程问题。

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

let $count在第1行定义了该变量的作用域,即其后的所有行。在第3行中,let $count定义了一个新的$count,其值为0+1,在其所属的代码块中有效 - 但该代码块未被定义。因此,您确实将$count增加了三次,但立即丢弃了结果。

BaseX的查询信息显示了此查询的优化版本,即:

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

解决方案

要获取$collection中元素的总数,您只需要使用以下方法:

return count($collection)

如果您需要一份XQuery函数列表,可以查看functx的XQuery部分,其中包含了XQuery函数列表以及其他一些有用的函数,这些函数可以作为模块来引用。


我不确定你的示例是否可以运行,或者说,我在运行它时遇到了问题。你能详细说明一下吗? - Thufir

6
英译中:

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

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=上尝试此示例。

3
XQuery脚本是一些XQuery实现提供的扩展。如果你想同时进行更新和返回元素(例如用于Web服务)时使用它非常好,但会阻止许多可能的优化。尽可能使用基本的XQuery。 - Jens Erat
实时示例已过期(404):( - ᴠɪɴᴄᴇɴᴛ
根据@JensErat的评论,这至少在BaseX中会崩溃 - 但还有什么其他的解决方法吗? - Thufir

4
请使用xdmp:set替代下面的查询。
let $count := 0
for $prod in (1 to 4)
return ( xdmp:set($count,number($count+1)) ,<counter>{$count }</counter> 

2
我认为您正在寻找类似以下内容的东西:
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>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接