data()
仅仅因为参数类型是,就返回空元素node()
对我来说听起来像是一个错误。您使用什么 XQuery 处理器?
听起来您需要安抚静态类型检查,您可以使用treat as
表达。我不相信使用动态测试instance of
就足够了。
尝试这个:
let $parameter := someNamespace:functionX() treat as element()
return local:myFunction($parameter)
引用迈克尔·凯的巨著第四版,“treat as
运算符本质上是告诉系统您知道运行时类型是什么,并且您希望将任何检查推迟到运行时,因为您确信您的代码是正确的。”(第 679 页)
UPDATE:我认为上面的说法实际上是错误的,因为treat as
只是一个断言。它不会更改类型注释node()
,这意味着这也是一个错误的断言,对您没有帮助。嗯...我真正想要的是cast as
,但这仅适用于原子类型。我想我被难住了。也许您应该更改 XQuery 引擎。 :-) 如果我想到其他事情,我会报告。另外,我很想知道 Dimitre 的解决方案是否适合您。
更新#2:我早些时候在这里退缩了。我还能再退一步吗? ;-) 现在我的理论是treat as
will工作基于以下事实node()
被解释为各种特定节点类型注释的联合,而不是作为运行时类型注释本身(请参阅XQuery 形式语义的“项目类型”部分 http://www.w3.org/TR/xquery-semantics/#sec_item_types.) 在运行时,类型注释将是element()
. Use treat as
向类型检查器保证这是真的。现在我屏息以待:这对你有用吗?
解释性附录:假设这有效,原因如下。node()
是联合类型。运行时的实际项目永远不会被注释为node()
。 “项目类型可以是原子类型、元素类型、属性类型、文档节点类型、文本节点类型、注释节点类型或处理指令类型。”1 http://www.w3.org/TR/xquery-semantics/#sec_item_types请注意node()
不在该列表中。因此,您的 XQuery 引擎不会抱怨某项具有类型node()
;相反,它抱怨它没有know类型将会是什么(node()
意味着它最终可能会成为attribute()
, element()
, text()
, comment()
, processing-instruction()
, or document-node()
)。为什么它必须知道?因为你在其他地方告诉它它是一个元素(在你的函数的签名中)。仅将其范围缩小到上述六种可能性之一是不够的。静态类型检查意味着您必须在编译时保证类型匹配(在本例中是元素与元素)。treat as
用于从通用类型中缩小静态类型的范围(node()
)到更具体的类型(element()
)。它不会改变动态类型。cast as
另一方面,用于将项目从一种类型转换为另一种类型,同时更改静态和动态类型(例如,xs:string 到 xs:boolean)。这是有道理的cast as
只能与原子值(而不是节点)一起使用,因为将属性转换为元素(等)意味着什么?并且不存在转换这样的事情node()
项目到element()
项目,因为没有这样的东西node()
item. node()
仅作为静态联合类型存在。故事的道德启示?避免使用静态类型检查的 XQuery 处理器。 (很抱歉得出了尖刻的结论;我觉得我已经赢得了权利。:-))
基于更新信息的新答案:听起来静态类型检查是一个转移注意力的话题(一条大鱼)。我相信你事实上not处理一个元素但是一个文档节点,它是不可见的根节点,包含格式良好的 XML 文档的 XPath 数据模型表示中的顶级元素(文档元素)。
因此,树的模型如下:
[document-node]
|
<docElement>
|
<subelement>
and not像这样:
<docElement>
|
<subelement>
我原以为你会通过<docElement>
节点。但如果我是对的,您实际上正在传递文档节点(其父节点)。由于文档节点是不可见的,因此它的序列化(您复制和粘贴的内容)与元素节点无法区分,并且当您在 XQuery 中粘贴现在被解释为裸元素构造函数的内容时,区别就消失了。 (要在 XQuery 中构造文档节点,您必须将元素构造函数包装为document{ ... }
.)
The instance of
测试失败,因为节点not一个元素,但一个文档节点。 (这不是一个node()
就其本身而言,因为不存在这样的事情;参见上面的解释。)
另外,这可以解释为什么data()
当您尝试获取时返回空<subelement>
文档节点的子节点(将函数参数类型放宽为node()
)。上面的第一个树表示表明<subelement>
is not文档节点的子节点;因此它返回空序列。
现在来说说解决方案。在传递(文档节点)参数之前,通过附加来获取其子元素(文档元素)/*
(or /element()
这是等效的)像这样:
let $parameter := someNamespace:functionX()/*
return local:myFunction($parameter)
或者,让您的函数采用文档节点并更新传递给 data() 的参数:
declare function local:myFunction($arg1 as document-node()) as element() {
let $value := data($arg1/*/subelement)
etc...
};
最后,它看起来像eXist请求说明:get-data()函数 http://demo.exist-db.org/exist/functions/request/get-data与这个解释完全一致。它说:“如果它不是二进制文档,我们会尝试将其解析为 XML并返回一个文档节点().”(强调)
感谢您的冒险。事实证明,这是一个常见的 XPath 陷阱(文档节点意识),但我从静态类型检查的绕行中学到了一些东西。