gpt4 book ai didi

xquery - XQuery中的element()与node()

转载 作者:行者123 更新时间:2023-12-04 17:12:04 24 4
gpt4 key购买 nike

有人可以告诉我XQuery中node()element()类型之间的确切区别吗?文档指出element()是元素节点,而node()是任何节点,因此如果我正确理解element()node()的子集。

事情是我有一个这样的XQuery函数:

declare function local:myFunction($arg1 as element()) as element() {
let $value := data($arg1/subelement)
etc...
};


现在,我想使用由另一个函数获得的参数调用该函数,例如 functionX(我无法控制):

let $parameter := someNamespace:functionX()
return local:myFunction($parameter)


问题是, functionX返回一个 node(),所以它不会让我直接传递 $parameter。我尝试将函数的类型更改为采用 node()而不是 element(),但随后似乎无法从中读取任何数据。 $value只是空的。

是否有某种将节点转换为元素的方法,还是我应该丢失某些东西?

编辑:据我所知,问题出在我尝试使用 $arg1/subelement获得子元素的部分。显然,如果 $arg1element(),则可以执行此操作,但如果它是 node(),则不能。

更新:我已经测试了下面Dimitre提供的示例,并且确实可以在Saxon和eXist DB(这就是我用作XQuery引擎)上正常工作。实际上,eXist DB中的 request:get-data()函数会出现此问题。当通过REST使用eXist时,此函数获取POST请求提供的数据,将其解析为XML并将其作为 node()返回。但是出于某种原因,当我将数据传递给另一个函数时,XQuery不会承认它是有效的 element(),即使它是。如果我手动提取它(即复制输出并将其粘贴到我的源代码中),则将其分配给一个变量并将其传递给我的函数,一切顺利。但是,如果我直接通过它,则会给我一个运行时错误(并确实导致 instance of测试失败)。

我需要能够使它忽略此类型检查,或者将数据“类型转换”为 element()

最佳答案

data()仅因为参数类型为node()而为元素返回空,这对我来说似乎是个错误。您正在使用什么XQuery处理器?

听起来您需要进行静态类型检查,可以使用treat as表达式来完成。我不相信使用instance of进行动态测试就足够了。

试试这个:

let $parameter := someNamespace:functionX() treat as element()
return local:myFunction($parameter)


引自迈克尔·凯(Michael Kay)的第四版大著述,“ treat as运算符实质上是在告诉系统您知道运行时类型是什么,并且您希望将任何检查推迟到运行时进行,因为您有信心您的代码是正确的。” (第679页)

更新:我认为以上实际上是错误的,因为 treat as只是一个断言。它不会更改类型注释 node(),这意味着它也是一个错误的断言,并且对您没有帮助。嗯...我真正想要的是 cast as,但这仅适用于原子类型。我想我很沮丧。也许您应该更改XQuery引擎。 :-)如果我有其他想法,我会报告。另外,我很想知道Dimitre的解决方案是否适合您。

更新#2:我早些时候在这里退缩了。我可以再次踩踏板吗? ;-)现在我的理论是 treat as将基于以下事实工作: node()被解释为各种特定节点类型注释的并集,而不是运行时类型注释本身(请参见“注意”在 "Item types" section of the XQuery formal semantics中。)在运行时,类型注释将为 element()。使用 treat as向类型检查器保证这将是正确的。现在,我屏息呼吸:它对您有用吗?

解释性附录:假设这可行,这就是原因。 node()是联合类型。运行时的实际项目永远不会用 node()注释。 “项目类型可以是原子类型,元素类型,属性类型,文档节点类型,文本节点类型,注释节点类型或处理指令类型。” 1注意, node()不是在该列表中。因此,您的XQuery引擎不会抱怨某个项目的类型为 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())来获取其元素子元素(document元素),如下所示:

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


最后,看起来 description of eXist's request:get-data() function与该解释完全一致。它说:“如果它不是二进制文档,我们将尝试将其解析为XML并返回document-node()。” (添加了重点)

感谢您的冒险。原来这是常见的XPath陷阱(文档节点的意识),但是我从绕道学习到静态类型检查中学到了一些东西。

关于xquery - XQuery中的element()与node(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8554543/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com