为什么XQuery中的数值文本永远不能是xs:positiveInteger类型?

为什么XQuery中的数值文本永远不能是xs:positiveInteger类型?,xquery,xquery-3.1,Xquery,Xquery 3.1,我注意到XQuery实现在处理(子)类型方面的细微差别。特别是,将文字数字作为输入处理到已声明接受输入类型的函数。 我天真地认为,任何可转换为特定数字类型的数字文字都会被接受 declare function local:any ($n as xs:anyAtomic) { $n }; declare function local:decimal ($n as xs:decimal) { $n }; declare function local:integer ($n as xs:integer

我注意到XQuery实现在处理(子)类型方面的细微差别。特别是,将文字数字作为输入处理到已声明接受输入类型的函数。 我天真地认为,任何可转换为特定数字类型的数字文字都会被接受

declare function local:any ($n as xs:anyAtomic) { $n };
declare function local:decimal ($n as xs:decimal) { $n };
declare function local:integer ($n as xs:integer) { $n };
declare function local:pos-int ($n as xs:positiveInteger) { $n };

local:any(1), (: works :)
local:decimal(1), (: works :)
local:integer(1), (: works :)
local:pos-int(1)  (: throws in all tested implementations :)
exist db允许
xs:long
xs:int
。。。撒克逊人没有

我在Xquery规范中找不到这种行为的任何原因 nor Xpath函数规范

这里有人能解释一下为什么Saxon 9.3.1他、BaseX 9.3.1[独立]和eXist 5.3.0-SNAPSHOT会这样做吗

我是否错过了规范中定义将文本
1
转换为xs:integer的部分? xs:decimal作为最顶层的类型会更有意义,但是如果允许使用一个子类型,为什么不一直使用呢


您可以将数值文本
1
传递给MarkLogic中的
local:pos-int()
函数:

declare function local:any($n as xs:anyAtomicType ) { $n };
declare function local:decimal($n as xs:decimal) { $n };
declare function local:integer($n as xs:integer) { $n };
declare function local:pos-int($n as xs:positiveInteger) { $n };

local:any(1), (: works :)
local:decimal(1), (: works :)
local:integer(1), (: works :)
local:pos-int(1)  (: works fine in MarkLogic :)
您可以使用报告返回的值属于类型
positiveInteger

xquery version "1.0-ml";
declare function local:pos-int($n as xs:positiveInteger) { $n };
xdmp:type(local:pos-int(1))
指定允许的促销类型:

数字类型升级:

xs:float类型的值(或通过限制从 xs:float)可以升级为xs:double类型。结果是 xs:与原始值相同的双精度值

xs:decimal类型的值(或通过限制从 xs:decimal)可以升级为xs:float或 xs:双倍。此促销的结果是通过铸造 将原始值转换为所需类型。这种促销可能会导致 精度损失


对于其他类型,您必须显式地使用构造函数,例如
local:int(xs:int(1))

我认为这方面的规范是非常不幸的,但很明显:值只有在标记为这样的情况下才是
xs:positiveInteger
,而不仅仅是因为它是(a)整数和(b)正数。XQuery工作组对此进行了长时间的讨论,涉及到编程语言类型系统方面的一些著名专家(如Phil Wadler),这就是我们做出的决定。我自己也不喜欢

说明书上怎么说的?XDM规范中的定义是一个良好的开端:

[定义:原子值是一个元素的值空间中的值 原子类型,并标有该原子类型的名称。]

[定义:原子类型是基元简单类型或 通过限制从另一个原子类型派生。](通过 列表或联合不是原子的。)

[定义:基本简单类型是2.1.1中定义的类型 从XML架构中采用的类型。]

XQuery规范中的§3.1.1谈到了数字文字:

不包含“.”且不包含e或e的数值文字的值 字符是xs:integer类型的原子值

§3.18.1给出了运营商“实例”的规则:

如果其值为 第一个操作数与其第二个操作数中的SequenceType匹配, 根据SequenceType匹配规则

§2.5.5.2给出了SequenceType匹配的相关规则:

仅由EQName组成的ItemType被解释为 原子型。预期的类型AtomicOrUnionType与 实际类型为AT的原子值,如果从(AT, AtomicOrUnionType)是真的

综上所述,其结果是xs:positiveInteger的表达式
3实例返回false(因为
xs:integer
不是从
xs:positiveInteger
派生的)

最后,当函数参数的预期类型为
xs:positiveInteger
,且函数调用提供值3时,§3.1.5.2中的函数转换规则起作用。它们允许从提供的值到所需类型的各种转换,但从xs:integer到xs:positiveInteger的“下转换”不在其中。所以这是一个错误:

如果在上述转换之后,结果值不匹配 根据SequenceType匹配规则的预期类型 引发类型错误[err:XPTY0004]


正如我所说,我不喜欢这些规则,并且在许多场合试图改变它们。但是它们是明确的,任何不遵循它们的产品都是不一致的。

示例代码中的语法有点不一致。与其说是
declare local:any function(…
,不如说是
declare function local:any(…
)。我为exist打开了一个问题,谢谢你详尽的回答。我很确定,我错过了规范。从@Micheal Kay和@Martin Honnen给出的答案来看,这似乎不符合规范(正如exist db允许对
xs:long
及其子类型进行向下转换的行为一样)。令人感兴趣的是,这些产品是否允许将十进制值1.3传递给期望xs:integer的函数?我之所以这样问,是因为与纯“向下转换”不同,向下转换允许这样做它只检查值的一致性,不进行任何转换。当使用值
1.3
执行时,会引发以下强制错误:
[1.0-ml]XDMP-AS:(err:XPTY0004)$n AS xs:positiveInteger--无效强制:1.3 AS xs:positiveInteger