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