【问题标题】:Xquery: not working case expression in a switch functionXquery:switch 函数中的 case 表达式不起作用
【发布时间】:2018-01-10 15:12:06
【问题描述】:

我在多次测试后提出这个问题,以验证我的表达是否正确。它是,虽然它仍然没有通过。

我正在使用经典的 dispatch/passthru 函数将 XML 数据库(具有使用命名空间 spip 的自己的架构)转换为 XML 文件(使用另一个架构)。

declare function p($node as element(spip:p)+, $options as map(*)) {
  switch ($node)
  case ( $node/spip:* instance of element(spip:img)        and fn:not($node/text()[fn:normalize-space(.) != '']) ) return passthru($node, $options)
  case ( $node/spip:* instance of element(spip:figure)     and fn:not($node/text()[fn:normalize-space(.) != '']) ) return passthru($node, $options)
  case ( $node/spip:* instance of element(spip:blockquote) and fn:not($node/text()[fn:normalize-space(.) != '']) ) return passthru($node, $options)
  default return
    <para>
      <alinea>{ passthru($node, $options) }</alinea>
    </para>
};

case 表达式主要测试&lt;p&gt; 元素中子元素($node/spip:*) 的性质以及该&lt;p&gt; 元素是否包含一些文本。有用!至少对于 &lt;blockquote&gt;&lt;figure&gt; 的孩子来说,但它不适用于元素 &lt;img&gt;

具有&lt;p&gt;&lt;img/&gt;&lt;/p&gt; 结构的节点正在通过默认情况,而像 &lt;p&gt;&lt;blockquote&gt;xxx&lt;/blockquote&gt;&lt;/p&gt;&lt;p&gt;&lt;figure&gt;xxx&lt;/figure&gt;&lt;/p&gt; 这样的节点正在通过测试。

我尝试更具体地测试&lt;img&gt; 元素:

case ($node/child::*[1] instance of element(spip:img))

奇怪的是,两个测试都在 if then else 表达式中正常工作。然后我就有了我想要的结果..

关于改进测试和妥善处理&lt;p&gt;&lt;img/&gt;&lt;/p&gt; 的任何建议?

【问题讨论】:

    标签: xml switch-statement xquery


    【解决方案1】:

    switch case 将原子化项目并比较它的原子化值以判断 case 子句是否相等。

    在 switch 表达式中,switch 关键字后跟一个用括号括起来的表达式,称为 switch 操作数表达式。这是正在比较其值的表达式。

    同样,typeswitch case clause 中的表达式计算节点的类型

    每个 case 子句都指定一个SequenceType,后跟一个返回表达式。

    您的 switch 没有按您预期的方式工作的原因是您正在测试类型和评估内容以产生一个布尔值,它不等于的原子化值正在测试的节点。

    您可以将计算测试值的逻辑上移到您的 case 语句中正在测试的 switch 表达式中。例如,生成一个连接namespace-uri()local-name()text() 值的字符串值

    declare function local:p($node as element(spip:p)+, $options) {
      let $namespace-uri := namespace-uri-from-QName(xs:QName("spip:foo")) (: you could hard-code the namespace-uri as well :)
      return
      switch (concat($node/*/namespace-uri(), $node/*/local-name(), $node/text()[normalize-space(.)]))
        case ( concat($namespace-uri, "img") ) return local:passthru($node, $options)
        case ( concat($namespace-uri, "figure") ) return local:passthru($node, $options)
        case ( concat($namespace-uri, "blockquote") ) return local:passthru($node, $options)
        default return
          <para>
            <alinea>{ local:passthru($node, $options) }</alinea>
          </para>
    };
    

    但是,您可能应该坚持使用if then else

    您可以结合测试中的标准来减少 if/else 块的数量:

    declare function p($node as element(p)+, $options as map(*)) {
      if (
        (
          $node/* instance of element(spip:img) 
          or $node/* instance of element(spip:figure) 
          or $node/* instance of element(spip:blockquote)
        ) 
        and not($node/text()[fn:normalize-space(.)])
      ) then 
        local:passthru($node, $options) 
      else 
        <para>
          <alinea>{ local:passthru($node, $options) }</alinea>
        </para>
    };
    

    【讨论】:

    • 确实,这就是我使用switch 而不是typeswitch 的原因。但你是对的,我用if then else 得到了正确的结果。但是,我的“案例”比我的示例中的更多,因此代码看起来有点混乱。仍然想知道为什么我的测试/表达式在ifcase 中的评估方式不同。感谢您的帮助。
    • 哎呀,我在调查解释时混合了switchtypeswitch。我已经更新了答案,但基本问题基本相同。使用 switch 更容易(提供示例),但使用 if/else 块可能更清晰、更易于阅读
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多