代码之家  ›  专栏  ›  技术社区  ›  me.at.coding

在XQuery中更新变量-可能还是不可能?

  •  5
  • me.at.coding  · 技术社区  · 14 年前

    在[1]上写着:

    无法更新变量。这意味着你不能写像let$x:=$x+1这样的东西。如果您希望XQuery的行为方式与JavaScript等过程语言相同,那么这个规则可能看起来非常奇怪。但是XQuery不是那种语言,它是一种声明性语言,在更高的层次上工作。对于不同表达式的执行顺序没有任何规则(这意味着在stylusstudioxquery调试器和XSLT调试器中显示当前执行点的小黄色三角形有时会以令人惊讶的方式运行),这意味着其结果将取决于执行顺序的构造(如变量赋值)将被禁止。

    [1] http://www.stylusstudio.com/xquery_flwor.html ,下面第二段是“L代表LET”一章的截图

    更新:

    6 回复  |  直到 14 年前
        1
  •  7
  •   Robert Harvey    14 年前

    你在描述不变性,一种 functional languages. 这是真的;一旦一个变量被设置为一个值,它就不能被设置为其他值。

    不变性有很多好处。特别地, concurrent programming 变得容易多了。

    是否有一个变量正在更新 当你写一些像

    for $v in //video
    let $x := xs:int($v/runtime) * xdt:dayTimeDuration("PT1M")
    return concat($v/title, ": ", 
          hours-from-duration($x), " hour(s) ",
          minutes-from-duration($x), " minutes")
    

    (此查询显示 每个视频。它首先将 从字符串到 整数,然后将其乘以1 获取运行时间的分钟数(PT1M) 持续时间。试试看。)

    这里变量$x有不同的 每次在XQuery中为 循环。这感觉有点像更新。 但从技术上讲,每次都是这样 你正在创建一个新的for循环 具有新值的变量,而不是 将新值赋给旧值 变量。

        2
  •  7
  •   Dennis Münkle    10 年前

    XQuery脚本扩展1.0

    Zorba Sandbox :

    declare namespace an = "http://zorba.io/annotations";
    
    declare %an:sequential function local:fib(){
      variable $a as xs:integer := 0;
      variable $b as xs:integer := 1;  
      variable $c as xs:integer := $a + $b;
      variable $fibseq as xs:integer* := ($a, $b);
      while ($c < 100) { 
         $fibseq := ($fibseq, $c);
         $a := $b;
         $b := $c;
         $c := $a + $b; 
      } 
      $fibseq
    };
    
    local:fib()
    

    顺序函数可以进行更新。apply语句(每段代码以 ; )立即应用所有更新。

    如果您只想在FLWOR中有一个计数变量,您可以使用 at 关键字:

    for $item at $x in ("a","b","c")
    return $x
    

    退货:

    <?xml version="1.0" encoding="UTF-8"?>
    1 2 3
    
        3
  •  3
  •   Cefn Hoile    13 年前

    你不能改变一个变量的值(一个愚蠢的名字不是吗,因为它们没有变化!)。

    将XQuery与任何复杂逻辑(以及可变变量之类的逻辑)结合使用的魔力在于递归。

    robertharvey提到了for循环的语言结构,其中变量每次都会发生变化,这是非常相关的,但这并不能总是解决问题,除非您的预期行为可以通过简单的列表迭代来实现。你要的是可变变量。

    从程序性(步骤的顺序执行)思维方式转变为功能性(同时评估从句)思维方式可能有点令人头晕。

    注意变量$patternsremaining严格来说是一个新变量(部分基于$patterns计算)。作为参数传递到递归调用中的任何模式都将在新函数调用中分配给$patterns。

    (: Here $patterns looks like <pattern match="something" replace="else" /> :)
    declare function local:transform($text as text(), $patterns as element(pattern)*) {
       if(not($patterns)) then 
          $text
       else
          let $patternsremaining := $patterns[position() > 1],
              $modifiedtext := replace($text, $pattern/@match, $pattern/@replace)
          return 
             if($local:language="French" and not($patterns[@match='le'])) then (
                 local:transform($modifiedtext, ($patternsremaining, <pattern match="Londres" replace="London" />))
          )
          else(
             local:transform($modifiedtext, $patternsremaining)
          )
    };
    

    对于使用XSLT和XQuery的硬核活动(例如编写编译器),递归是我发现的唯一具有足够能力的模型。然而,真实的例子看起来比上面的更复杂。

    至于if()then()else()语句,因为可能以前遇到过相同的执行上下文(如果您是过程编码人员,则认为是“堆栈变量的组合”),并且在其他地方已经对相同的表达式进行了求值,因此if语句将永远不会再次求值,因为解释器可以基于上一次调用缓存结果。因此,严格来说,你不能依赖序列。它可能根本不会运行!

    这是可能的,因为它内置于语言定义中,不存在会改变函数求值结果的副作用(因此这些变量不会变化)。

    这种可缓存性是函数方法的一个中心特性。它为编写高效的解释器创造了潜力,但如果您想能够使用可变值进行操作,就需要递归地思考。

        4
  •  0
  •   Matti Virkkunen    14 年前

    不,不能更新变量。如果你不能依赖执行顺序,那么这样做又有什么意义呢?

    当然,即使没有可更新的变量,您也可以使用递归函数执行几乎所有操作,包括变量递增的“循环”。这是有效的还是好的主意,则另当别论。我曾经实施过 sqrt()

        5
  •  0
  •   abdollar    14 年前

    相信我。

    在这方面,XQuery就像一种函数式编程语言。您不希望从函数/数学的角度更改已计算计算的计算值。此外,数据是不可变的,并且不能更改状态,因此可以使用该语言构建高并发性应用程序。Erlang是为高并发性而构建的语言的“好”例子。一些命令式语言(如Java)中也使用了不变性来实现高并发性。

    就像在任何其他函数式语言中一样,您可以始终确保“eval”您的“expr”,然后使用一个副本进行所需的更改。

    注意,我并不是说XQuery是一种好的函数式编程语言。看看erlang,它是一个很好的函数语言和实现的例子,可以提供很好的性能。