Xquery:无论是在switch/case还是if/then/else中使用,相同的测试都有不同的结果

lac*_*nis 6 xquery if-statement case switch-statement flwor

我无法找到以下解释.我已经制作了这个测试脚本以解决我之前的问题.

xquery version "3.0" ;
declare default function namespace 'local' ;

declare function local:is-img-only( $element as element() )  as xs:boolean {    
   ($element/child::*[1] instance of element(img)) 
   and (fn:not($element/child::*[2])) 
   and (fn:normalize-space($element) = '')
} ;

let $in-xml := <myxml>
   <p id="1">

      <img id="1"/>

   </p>
   <p id="2">
      <img id="1"/>
      hello
   </p>
   <p id="3">
      <img id="1"/>
   </p>
   <p id="4">
    <blockquote>hello</blockquote>
      <img id="1"/>
   </p>
   <p id="5">
      <img id="1"/>
      <img id="2"/>
   </p>
</myxml>
Run Code Online (Sandbox Code Playgroud)

然后,使用以下内容if then else:

for $p in $in-xml/p
  return if (local:is-img-only($p)) 
    then $p/@id/fn:data() || ' has only an img child'
    else $p/@id/fn:data() || ' has not strictly an img child'
Run Code Online (Sandbox Code Playgroud)

按预期返回:

1 has only an img child
2 has not strictly an img child
3 has only an img child
4 has not strictly an img child
5 has not strictly an img child  
Run Code Online (Sandbox Code Playgroud)

以下使用 switch case

for $p in $in-xml/p
  return switch ($p)
    case (local:is-img-only($p)) return $p/@id/fn:data() || ' has only an img child'
    default return $p/@id/fn:data() || ' has not strictly an img child'
Run Code Online (Sandbox Code Playgroud)

返回不是预期的:

1 has not strictly an img child
2 has not strictly an img child
3 has not strictly an img child
4 has not strictly an img child
5 has not strictly an img child
Run Code Online (Sandbox Code Playgroud)

任何解释?为什么条件表达式的行为与Switch Expressions不同

joe*_*wiz 4

非常出色地找到了与您的问题相关的 XQuery 规范部分!这样就成功了一半。开关表达式确实与条件表达式有一些共同点,但也存在一些差异。

\n\n

主要区别在于,条件表达式计算测试表达式以查看结果是 true 还是 false,而 switch 表达式将一个表达式与一个或多个其他表达式进行比较,以找到第一对相等的表达式。使用伪代码,我们可以说明其中的差异。条件表达式中的所有逻辑都发生在一行上:

\n\n
if ($EXPRESSION)\n
Run Code Online (Sandbox Code Playgroud)\n\n

相反,switch 表达式的逻辑分布在许多行中:

\n\n
switch ($EXPRESSION_A)\n    case ($EXPRESSION_B) ...\n    case ($EXPRESSION_C) ...\n    case ($EXPRESSION_D) ...\n    default ...\n
Run Code Online (Sandbox Code Playgroud)\n\n

switch 表达式实际上执行一系列比较,我们可以将其表示为更多行条件表达式:

\n\n
if (deep-equal($EXPRESSION_A, $EXPRESSION_B))\nthen ...\nelse \n    if (deep-equal($EXPRESSION_A, $EXPRESSION_C))\n    then ...\n    else ...\n        if (deep-equal($EXPRESSION_A, $EXPRESSION_D))\n        then ...\n        else ... (: "default" :)\n
Run Code Online (Sandbox Code Playgroud)\n\n

规范中描述了这两个表达式之间的本质差异,从它们描述处理每个表达式的“第一步”开始。而处理条件表达式的第一步是:

\n\n
\n

找到测试表达式的有效布尔值。

\n
\n\n

...处理 switch 表达式的第一步是:

\n\n
\n

将原子化应用于 switch 操作数表达式的值。

\n
\n\n

让我们回到具体的示例,看看条件的测试表达式和开关的开关操作数表达式:

\n\n
    \n
  1. 您的条件测试表达式:

    \n\n
    if (local:is-img-only($p)) \n
    Run Code Online (Sandbox Code Playgroud)
  2. \n
  3. 您的开关的操作数表达式:

    \n\n
    switch ($p)\n
    Run Code Online (Sandbox Code Playgroud)
  4. \n
\n\n

条件的测试表达式返回一个布尔值 -true()false(),因此此条件清楚地标出了其余代码的路径。

\n\n

相反,switch 表达式的逻辑才刚刚从这个操作数表达式开始。首先,它查找操作数表达式\xe2\x80\x94(<p>绑定到$pFLWOR 表达式中变量的元素)的原子化值。由于该值取决于<p>我们正在查看的值,因此原子化值将是空字符串 ( "")、空格或"hello"(或其某种组合,具体取决于源中的空格和边界空间声明)。然后,对 switch 的第一个 case 操作数进行求值和原子化。您的第一个案例操作数如下:

\n\n
case (local:is-img-only($p))\n
Run Code Online (Sandbox Code Playgroud)\n\n

正如我们所记得的,这个表达式的计算结果是一个布尔值。switch 表达式执行的下一步是使用以下命令将 switch 操作数表达式的原子化值与 switch case 操作数的原子化值进行比较:fn:deep-equal函数将 switch 操作数表达式的原子化值与 switch case 操作数的原子化值进行比较。那么,我们实际上要求 XQuery 处理器执行以下比较:

\n\n
deep-equal("", true())\ndeep-equal("hello", false())\n
Run Code Online (Sandbox Code Playgroud)\n\n

在这两种情况下,比较都会返回false(). 因此,我们的情况操作数中的比较总是失败,因此 switch 表达式会退回到default失败,因此 switch 表达式在 FLWOR 表达式的每次迭代中

\n\n

模仿原始条件表达式结果的 switch 表达式如下:

\n\n
for $p in $in-xml/p\n  return switch(local:is-img-only($p))\n    case (true()) return $p/@id/fn:data() || \' has only an img child\'\n    default return $p/@id/fn:data() || \' has not strictly an img child\'\n
Run Code Online (Sandbox Code Playgroud)\n\n

这将执行以下检查:

\n\n
deep-equal(true(), true())\ndeep-equal(true(), false())\n
Run Code Online (Sandbox Code Playgroud)\n\n

并返回与条件表达式相同的结果。

\n\n

对于 switch 表达式来说,这并不是特别引人注目的用途 - 因为我们正在有效地评估单个测试表达式。当您有许多值需要比较时,switch 表达式确实会发挥作用。该规范为我们提供了一个值得考虑的很好的 switch 表达式示例:

\n\n
switch ($animal)\n    case "Cow" return "Moo"\n    case "Cat" return "Meow"\n    case "Duck" return "Quack"\n    default return "What\'s that odd noise?"\n
Run Code Online (Sandbox Code Playgroud)\n\n

这比等效的条件表达式更具可读性和紧凑性:

\n\n
if (deep-equal($animal, "Cow")) \nthen "Moo"\nelse \n    if (deep-equal($animal, "Cat")) \n    then "Meow"\n    else\n        if (deep-equal($animal, "Duck"))\n        then "Quack"\n        else "What\'s that odd noise?"\n
Run Code Online (Sandbox Code Playgroud)\n\n

或者更直接的解释:

\n\n
if ($animal eq "Cow")\nthen "Moo"\nelse \n    if ($animal eq "Cat")\n    then "Meow"\n    else\n        if ($animal eq "Duck")\n        then "Quack"\n        else "What\'s that odd noise?"\n
Run Code Online (Sandbox Code Playgroud)\n\n

结果:如果您发现自己编写了一系列条件语句,并且比较的左侧始终相同,请考虑进行切换

\n