XQuery中的元素()与节点()

XQuery中的元素()与节点(),xquery,exist-db,Xquery,Exist Db,有人能告诉我XQuery中node()和element()类型之间的确切区别吗?文档说明element()是一个元素节点,而node()是任何节点,因此如果我理解正确的话element()是node()的一个子集 问题是我有这样一个XQuery函数: declare function local:myFunction($arg1 as element()) as element() { let $value := data($arg1/subelement) etc... };

有人能告诉我XQuery中
node()
element()
类型之间的确切区别吗?文档说明
element()
是一个元素节点,而
node()
是任何节点,因此如果我理解正确的话
element()
node()
的一个子集

问题是我有这样一个XQuery函数:

declare function local:myFunction($arg1 as element()) as element() {
    let $value := data($arg1/subelement)
   etc...
};
      [document-node]
             |
        <docElement>
             |
        <subelement>
        <docElement>
             |
        <subelement>
let $parameter := someNamespace:functionX()/*
return local:myFunction($parameter)
现在我想用另一个函数获得的参数调用函数,比如
functionX
(我无法控制):

问题是,
functionX
返回一个
节点()
,因此它不允许我直接传递
$参数。我尝试将函数的类型更改为使用
节点()
而不是
元素()
,但似乎无法从中读取任何数据<代码>$value
仅为空

是否有某种方法可以将节点转换为元素,或者我只是缺少了什么

编辑:据我所知,问题出在我尝试使用
$arg1/subelement
获取子元素的部分。显然,如果
$arg1
元素()
,则可以这样做,但如果它是
节点()
,则不能这样做

更新:我已经测试了下面Dimitre提供的示例,它在Saxon和eXist DB(我正在使用它作为XQuery引擎)上都运行良好。问题实际上发生在eXist DB的
请求:get-data()
函数中。此函数通过REST使用eXist时获取POST请求提供的数据,将其解析为XML,并将其作为
节点()返回。但是由于某种原因,当我将数据传递给另一个函数时,XQuery没有确认它是有效的
元素()
,即使它是有效的。如果我手动提取它(即复制输出并粘贴到我的源代码),将其分配给变量并将其传递给我的函数,一切都会顺利进行。但是如果我直接通过它,它会给我一个运行时错误(并且确实会使
测试的
实例失败)

我需要能够使其忽略此类型检查或将数据“类型转换”到
元素()

节点()
是元素、属性、处理指令、文本节点等

但是
data()
将结果转换为一个字符串,而不是这些字符串中的任何一个;这是一种原始类型

您可能需要尝试
item()
,该选项应与其中一项匹配

请参阅W3C XQuery规范中的


虽然示例代码中没有显示它,但我假设您实际上是从
local:myFunction

返回一个值(如您正在使用的
$value
),这在使用Saxon 9.3时非常有效:

declare namespace my = "my:my";
declare namespace their = "their:their";

declare function my:fun($arg1 as element()) as element() 
{
            $arg1/a
};

declare function their:fun2($arg1 as node()) as node() 
{
            $arg1
};

my:fun(their:fun2(/*) )
<t>
  <a/>
</t>
<a/>
将上述代码应用于以下XML文档时

declare namespace my = "my:my";
declare namespace their = "their:their";

declare function my:fun($arg1 as element()) as element() 
{
            $arg1/a
};

declare function their:fun2($arg1 as node()) as node() 
{
            $arg1
};

my:fun(their:fun2(/*) )
<t>
  <a/>
</t>
<a/>
data()
仅仅因为参数类型是
node()
就返回元素为空,这听起来像是一个bug。您使用的是什么XQuery处理器

听起来您需要安抚静态类型检查,您可以使用
作为
表达式处理。我认为使用
实例进行动态测试是不够的

试试这个:

let $parameter := someNamespace:functionX() treat as element()
return local:myFunction($parameter)
引用迈克尔·凯(Michael Kay)的代表作第四版,“将
视为
操作符本质上是告诉系统您知道运行时类型,并且您希望将任何检查推迟到运行时,因为您确信您的代码是正确的。”(第679页)

更新:我认为上面的说法实际上是错误的,因为
视为
只是一个断言。它不会更改类型注释
节点()
,这意味着它也是一个错误的断言,对您没有帮助。六羟甲基三聚氰胺六甲醚。。。我真正想要的是将
转换为
,但这只适用于原子类型。我想我被难住了。也许您应该更改XQuery引擎。:-)如果我想到别的事,我会向你汇报的。另外,我很想知道Dimitre的解决方案是否适合你

更新#2:我早些时候在这里倒车。我能再后退一次吗?;-)现在我的理论是,
treatas
将根据以下事实工作:
node()
被解释为各种特定节点类型注释的联合,而不是作为运行时类型注释本身(请参见中的“注释”)。在运行时,类型注释将是
element()
。使用
视为
向类型检查器保证这是真实的。现在我屏住呼吸:它对你有用吗

解释性附录:假设这是可行的,下面是原因<代码>节点()
是一种联合类型。运行时的实际项目从不使用
node()
注释。“项目类型可以是原子类型、元素类型、属性类型、文档节点类型、文本节点类型、注释节点类型或处理指令类型。”请注意,
node()
不在该列表中。因此,您的XQuery引擎不会抱怨某个项的类型为
node()
;相反,它抱怨它不知道类型是什么(
node()
意味着它最终可能是
attribute()
element()
text()
comment()
processing-instruction()
,或
document-node()
)。为什么一定要知道?因为你在别处告诉它它是一个元素(在你函数的签名中)。仅限于上述六种可能性之一是不够的。静态类型检查意味着您必须在编译时保证类型匹配(在本例中是元素对元素)
treatas
用于将静态类型从常规类型(
node()
)缩小到更具体的类型(
element()
)。它不会更改动态类型<另一方面,代码>转换为
,用于转换项目fr