Xquery:在switch函数中不是工作表达式

时间:2018-01-10 15:12:07

标签: xml switch-statement xquery

我在多次测试后提出这个问题,以验证我的表达是否正确。它确实如此,但它仍然没有经历过。

我使用经典的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表达式基本上测试$node/spip:*元素中子元素(<p>)的性质以及此<p>元素是否包含一些文本。有用!至少对于孩子<blockquote><figure>,但它不适用于元素<img>

具有该结构的节点<p><img/></p>正在经历默认情况,而<p><blockquote>xxx</blockquote></p><p><figure>xxx</figure></p>等节点正在通过测试。

我试图通过以下方式更详细地测试<img>元素:

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

奇怪的是,两个测试在if then else表达式中都运行良好。然后我得到了我想要的结果..

有任何改进测试和<p><img/></p>正确对待的建议吗?

1 个答案:

答案 0 :(得分:2)

switch一个案例将雾化该项并将其与雾化值进行比较以获得case子句的相等性。

  

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

类似地,typeswitch case clause中的表达式评估节点的类型

  

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

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

您可以将用于计算测试值的逻辑移动到您在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>
};