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变量更新失败或被重置。为什么我不能重新分配现有变量?获得预期结果的更好方法是什么?

4

7 回答 7

22

尝试使用'at'

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>
于 2012-04-24T09:29:27.567 回答
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)

也就是说,在您的示例中,您绝对应该at $count按照@tohuwawohu 所示使用。

于 2012-04-24T10:01:27.283 回答
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=现场试用此示例

于 2012-04-24T11:55:15.920 回答
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可能会有所帮助。

于 2012-04-24T18:50:56.330 回答
6

不可变变量

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 函数列表,您可以查看functx 的 XQuery 部分,它既包含 XQuery 函数列表,也包含其他一些可以作为模块包含的有用函数。

于 2012-04-24T09:16:49.083 回答
4

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

let $count := 0
for $prod in (1 to 4)
return ( xdmp:set($count,number($count+1)) ,<counter>{$count }</counter> 
于 2015-03-04T12:23:18.523 回答
2

我认为您正在寻找类似的东西:

查询:

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>
于 2013-04-18T04:43:05.470 回答