Xquery:在 switch 函数中不工作的 case 表达式 [英] Xquery: not working case expression in a switch function

查看:25
本文介绍了Xquery:在 switch 函数中不工作的 case 表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

declare function p($node as element(spip:p)+, $options as map(*)) {开关($节点)case ( $node/spip:* element(spip:img) 和 fn:not($node/text()[fn:normalize-space(.) != '']) 的实例) return passthru($node, $选项)case ( $node/spip:* element(spip:figure) 和 fn:not($node/text()[fn:normalize-space(.) != '']) 的实例) return passthru($node, $选项)case ( $node/spip:* 元素实例(spip:blockquote) 和 fn:not($node/text()[fn:normalize-space(.) != '']) ) return passthru($node, $选项)默认回报<段><alinea>{ passthru($node, $options) }</alinea>};

case 表达式基本上测试 <p> 元素中的子元素 ($node/spip:*) 的性质以及这个 <p> 元素包含一些文本.有用!至少对于子元素

,但它不适用于元素 .

具有该结构的节点

正在经历默认情况,而像

这样的节点会经历默认情况.xxx</blockquote></p><p><figure>xxx</figure></p> 正在通过测试.

我试图更具体地测试 <img> 元素:

case ($node/child::*[1] 元素实例(spip:img))

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

对于改进测试和<p><img/></p>有什么建议吗?

解决方案

A switch case 将原子化项目并比较它的原子化值是否与 case 子句相等.

<块引用>

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

类似地,typeswitch case 子句中的表达式计算节点类型.

<块引用>

每个 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")) (: 你也可以硬编码 namespace-uri :)返回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)默认回报<段><alinea>{ local:passthru($node, $options) }</alinea>};

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

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

declare function p($node as element(p)+, $options as map(*)) {如果 (($node/* 元素实例(spip:img)或 $node/* 元素实例(spip:figure)或 $node/* 元素实例(spip:blockquote))而不是($node/text()[fn:normalize-space(.)])) 然后本地:passthru($node,$options)别的<段><alinea>{ local:passthru($node, $options) }</alinea>};

I raise this question after multiples tests in order to verify that my expression is correct. And it is, although it still doesn't go through.

I'm using the classic dispatch/passthru function to convert an XML database (with its own schema using the namespace spip) to XML files (with another schema).

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>
};

The case expressions basically test the nature of the child element ($node/spip:*) in a <p> element and whether this <p> element contains some text. It works! At least for the childs <blockquote> and <figure>, but it doesn't for the element <img>.

Nodes with that structure <p><img/></p> are going through the default case, whereas nodes like <p><blockquote>xxx</blockquote></p> or <p><figure>xxx</figure></p> are passing the test.

I have tried to be more specific in testing the <img> element with :

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

The weird thing is that both tests are working fine in a if then else Expression. Then I have the result I want..

Any suggestion.s for improving the tests and having <p><img/></p> properly treated ?

解决方案

A switch case will atomize the item and compare it's atomized value for equality of the case clause.

In a switch expression, the switch keyword is followed by an expression enclosed in parentheses, called the switch operand expression. This is the expression whose value is being compared.

Similarly, the expression in a typeswitch case clause evaluates the type of node.

Each case clause specifies a SequenceType followed by a return expression.

The reason why your switch isn't working the way that you expect is that you are testing both the type and evaluating the content to produce a boolean value, which does not equal the atomized value of the node being tested.

You could move the logic for computing the tested value up into the switch expression being tested in your case statement. For instance, produce a string value that concatenates the namespace-uri(), local-name(), and the value of the text() value

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>
};

However, you should probably just stick with the if then else.

You could combine the criteria in your tests to reduce the number of if/else blocks:

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>
};

这篇关于Xquery:在 switch 函数中不工作的 case 表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆