Xquery:无论在 switch/case 还是 if/then/else 中使用相同的测试都有不同的结果
Xquery: same test has different result whether used in switch/case or in if/then/else
我找不到以下内容的解释。我制作了这个测试脚本以解决 .
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>
然后,下面使用 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'
returns 符合预期:
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
而以下使用 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'
returns 出乎意料:
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
有什么解释吗?为什么 Conditional Expressions would not behave the same way than Switch Expressions ?
为您的问题找到 XQuery 规范的相关部分真是太棒了!这是成功的一半。开关表达式确实与条件表达式有一些共同之处,但也有一些不同之处。
主要区别在于条件表达式 评估测试表达式 以查看结果是真还是假,而开关表达式 将一个表达式与一个或多个其他表达式 以找到第一对相等的表达式。使用伪代码,我们可以说明差异。条件表达式中的所有逻辑都集中在一行中:
if ($EXPRESSION)
相比之下,switch 表达式的逻辑分布在多行中:
switch ($EXPRESSION_A)
case ($EXPRESSION_B) ...
case ($EXPRESSION_C) ...
case ($EXPRESSION_D) ...
default ...
switch 表达式实际上是在执行一系列比较,我们可以将其表示为更多行的条件表达式:
if (deep-equal($EXPRESSION_A, $EXPRESSION_B))
then ...
else
if (deep-equal($EXPRESSION_A, $EXPRESSION_C))
then ...
else ...
if (deep-equal($EXPRESSION_A, $EXPRESSION_D))
then ...
else ... (: "default" :)
规范中描述了这两个表达式之间的细微差别,从它们在处理每个表达式时描述 "the first step" 的地方开始。而处理条件表达式的第一步是:
to find the effective boolean value of the test expression.
...处理switch表达式的第一步是:
to apply atomization to the value of the switch operand expression.
让我们return看一下您的具体示例,看看您的条件测试表达式和开关的开关操作数表达式:
您的条件测试表达式:
if (local:is-img-only($p))
您的开关的操作数表达式:
switch ($p)
条件的测试表达式 return 是一个布尔值 - true()
或 false()
,所以这个条件清楚地标出了其余代码的路径。
相比之下,switch表达式的逻辑从这个操作数表达式才刚刚开始。首先,它找到操作数表达式的原子化值——绑定到 FLWOR 表达式中的 $p
变量的 <p>
元素。由于此值取决于我们正在查看的 <p>
,原子化值将是空字符串 (""
)、白色 space 或 "hello"
(或一些它们的组合,取决于源代码中的 whitespace 和边界 space 声明)。然后,对 switch 的第一个 case 操作数进行求值和原子化。您的第一个 case 操作数如下:
case (local:is-img-only($p))
我们会记得,这个表达式的计算结果是一个布尔值。 switch 表达式执行的下一步是使用 fn:deep-equal
函数将 switch 操作数表达式的原子化值与 switch case 操作数的原子化值进行比较。那么,实际上,我们要求 XQuery 处理器执行以下比较:
deep-equal("", true())
deep-equal("hello", false())
在这两种情况下比较returns false()
。因此,在我们的案例操作数 always 中,这种比较总是失败,因此 switch 表达式在 FLWOR 表达式的每次迭代中都返回到 default
子句。
模拟原始条件表达式结果的开关表达式如下:
for $p in $in-xml/p
return switch(local:is-img-only($p))
case (true()) return $p/@id/fn:data() || ' has only an img child'
default return $p/@id/fn:data() || ' has not strictly an img child'
这会执行以下检查:
deep-equal(true(), true())
deep-equal(true(), false())
并且 return 与您的条件表达式的结果相同。
这不是 switch 表达式的特别引人注目的用途 - 因为我们正在有效地评估单个测试表达式。当您有很多值要比较时,switch 表达式真的很出色。该规范为我们提供了一个很好的示例开关表达式来考虑:
switch ($animal)
case "Cow" return "Moo"
case "Cat" return "Meow"
case "Duck" return "Quack"
default return "What's that odd noise?"
这比等效的条件表达式更具可读性和紧凑性:
if (deep-equal($animal, "Cow"))
then "Moo"
else
if (deep-equal($animal, "Cat"))
then "Meow"
else
if (deep-equal($animal, "Duck"))
then "Quack"
else "What's that odd noise?"
或者更直接的解释:
if ($animal eq "Cow")
then "Moo"
else
if ($animal eq "Cat")
then "Meow"
else
if ($animal eq "Duck")
then "Quack"
else "What's that odd noise?"
结果:如果您发现自己编写了一系列条件,并且比较的左侧始终相同,请考虑进行转换。
我找不到以下内容的解释。我制作了这个测试脚本以解决
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>
然后,下面使用 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'
returns 符合预期:
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
而以下使用 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'
returns 出乎意料:
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
有什么解释吗?为什么 Conditional Expressions would not behave the same way than Switch Expressions ?
为您的问题找到 XQuery 规范的相关部分真是太棒了!这是成功的一半。开关表达式确实与条件表达式有一些共同之处,但也有一些不同之处。
主要区别在于条件表达式 评估测试表达式 以查看结果是真还是假,而开关表达式 将一个表达式与一个或多个其他表达式 以找到第一对相等的表达式。使用伪代码,我们可以说明差异。条件表达式中的所有逻辑都集中在一行中:
if ($EXPRESSION)
相比之下,switch 表达式的逻辑分布在多行中:
switch ($EXPRESSION_A)
case ($EXPRESSION_B) ...
case ($EXPRESSION_C) ...
case ($EXPRESSION_D) ...
default ...
switch 表达式实际上是在执行一系列比较,我们可以将其表示为更多行的条件表达式:
if (deep-equal($EXPRESSION_A, $EXPRESSION_B))
then ...
else
if (deep-equal($EXPRESSION_A, $EXPRESSION_C))
then ...
else ...
if (deep-equal($EXPRESSION_A, $EXPRESSION_D))
then ...
else ... (: "default" :)
规范中描述了这两个表达式之间的细微差别,从它们在处理每个表达式时描述 "the first step" 的地方开始。而处理条件表达式的第一步是:
to find the effective boolean value of the test expression.
...处理switch表达式的第一步是:
to apply atomization to the value of the switch operand expression.
让我们return看一下您的具体示例,看看您的条件测试表达式和开关的开关操作数表达式:
您的条件测试表达式:
if (local:is-img-only($p))
您的开关的操作数表达式:
switch ($p)
条件的测试表达式 return 是一个布尔值 - true()
或 false()
,所以这个条件清楚地标出了其余代码的路径。
相比之下,switch表达式的逻辑从这个操作数表达式才刚刚开始。首先,它找到操作数表达式的原子化值——绑定到 FLWOR 表达式中的 $p
变量的 <p>
元素。由于此值取决于我们正在查看的 <p>
,原子化值将是空字符串 (""
)、白色 space 或 "hello"
(或一些它们的组合,取决于源代码中的 whitespace 和边界 space 声明)。然后,对 switch 的第一个 case 操作数进行求值和原子化。您的第一个 case 操作数如下:
case (local:is-img-only($p))
我们会记得,这个表达式的计算结果是一个布尔值。 switch 表达式执行的下一步是使用 fn:deep-equal
函数将 switch 操作数表达式的原子化值与 switch case 操作数的原子化值进行比较。那么,实际上,我们要求 XQuery 处理器执行以下比较:
deep-equal("", true())
deep-equal("hello", false())
在这两种情况下比较returns false()
。因此,在我们的案例操作数 always 中,这种比较总是失败,因此 switch 表达式在 FLWOR 表达式的每次迭代中都返回到 default
子句。
模拟原始条件表达式结果的开关表达式如下:
for $p in $in-xml/p
return switch(local:is-img-only($p))
case (true()) return $p/@id/fn:data() || ' has only an img child'
default return $p/@id/fn:data() || ' has not strictly an img child'
这会执行以下检查:
deep-equal(true(), true())
deep-equal(true(), false())
并且 return 与您的条件表达式的结果相同。
这不是 switch 表达式的特别引人注目的用途 - 因为我们正在有效地评估单个测试表达式。当您有很多值要比较时,switch 表达式真的很出色。该规范为我们提供了一个很好的示例开关表达式来考虑:
switch ($animal)
case "Cow" return "Moo"
case "Cat" return "Meow"
case "Duck" return "Quack"
default return "What's that odd noise?"
这比等效的条件表达式更具可读性和紧凑性:
if (deep-equal($animal, "Cow"))
then "Moo"
else
if (deep-equal($animal, "Cat"))
then "Meow"
else
if (deep-equal($animal, "Duck"))
then "Quack"
else "What's that odd noise?"
或者更直接的解释:
if ($animal eq "Cow")
then "Moo"
else
if ($animal eq "Cat")
then "Meow"
else
if ($animal eq "Duck")
then "Quack"
else "What's that odd noise?"
结果:如果您发现自己编写了一系列条件,并且比较的左侧始终相同,请考虑进行转换。