在XQuery中更新计数器

时间:2012-04-24 08:53:04

标签: xquery marklogic

我想在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 个答案:

答案 0 :(得分:22)

尝试在:

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

这将为您提供每个'$ d'的位置。如果要将此与order by子句一起使用,则这将不起作用,因为该位置基于初始顺序,而不是基于排序结果。要解决这个问题,只需将FLWOR表达式的排序结果保存在变量中,并在第二个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>

答案 1 :(得分:8)

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

那就是说,在你的例子中,你绝对应该使用@ {huhuwohu所示的at $count

答案 2 :(得分:6)

不可变变量

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

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

let $count在所有范围内定义了此变量,在这种情况下,这些变量都是以下行。第3行中的let $count定义了一个新的$count 0+1,在此代码块中的所有后续行中有效 - 未定义。所以你确实将$count增加了三倍,但立即丢弃了结果。

BaseX'查询信息显示此查询的优化版本

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

解决方案

要获取$collection中的元素总数,您只需使用

即可
return count($collection)

有关XQuery函数的列表,您可以查看XQuery part of functx,其中包含XQuery函数列表以及一些其他有用的函数,这些函数可以作为模块包含在内。

答案 3 :(得分:6)

上面的所有解决方案都有效,但我想提一下,您可以使用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=

上试用此示例

答案 4 :(得分:6)

特定于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可能会有所帮助。

答案 5 :(得分:4)

使用xdmp:set代替以下查询

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

答案 6 :(得分: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>