【问题标题】:Updating counter in XQuery在 XQuery 中更新计数器
【发布时间】:2012-05-04 21:34:21
【问题描述】:

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

【问题讨论】:

    标签: xquery marklogic


    【解决方案1】:

    不可变变量

    XQuery 是一个functional programming language,其中涉及不可变变量,因此您无法更改变量的值。另一方面,强大的功能集合供您使用,解决了很多日常编程问题。

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

    【讨论】:

    • 我不确定您的示例是否运行,或者,至少,我无法运行它。你能详细说明吗?
    【解决方案2】:

    尝试使用 '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>
    

    【讨论】:

      【解决方案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)

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

      【讨论】:

        【解决方案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= 现场试用此示例

        【讨论】:

        • XQuery Scripting 是一些 XQuery 实现提供的扩展。如果您想同时进行更新和返回元素(例如,对于 Web 服务),则特别好,但会阻止许多可能的优化。您应该尽可能坚持使用基本的 XQuery。
        • 现场示例已过期(404):(
        • 根据@JensErat 的评论,这至少与BaseX 一起崩溃——但还有什么完成的?
        【解决方案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】:

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

          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>
          

          【讨论】:

            【解决方案7】:

            使用xdmp:set 代替下面的查询

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-07-02
              • 2012-03-13
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多