3

我注意到 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 :)

exists-db 允许xs:long, xs:int, ... Saxon 不允许。

我在 Xquery Spec 2.5.5 SequenceType Matching 和 Xpath functions spec 1.6.3 Atomic Type Hierarchy中找不到该行为的任何原因

有人可以解释一下为什么 Saxon 9.3.1 HE、BaseX 9.3.1 [Standalone] 和 eXist 5.3.0-SNAPSHOT 会这样吗?

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

这是一个现场演示

4

3 回答 3

6

我认为这方面的规范非常不幸,但很明显:一个值xs:positiveInteger只有当它被标记时才是一个,而不仅仅是因为它是 (a) 整数和 (b) 正数。XQuery 工作组对此进行了长时间的讨论,其中包括一些编程语言类型系统方面的知名专家(如 Phil Wadler),最终做出了决定。我自己不喜欢。

规范在哪里说这个?XDM 规范中的定义是一个好的开始:

https://www.w3.org/TR/xpath-datamodel-31/#xs-types

[定义:原子值是原子类型的值空间中的值,并以该原子类型的名称进行标记。]

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

[定义:原始简单类型是2.1.1 XML Schema采用的类型中定义的类型。]

然后 XQuery 规范中的 §3.1.1 讨论了数字文字:

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

§3.18.1 给出了“instance of”运算符的规则:

instance of根据 SequenceType 匹配规则,如果布尔运算符的第一个操作数的值与第二个操作数中的 SequenceType 匹配,则布尔运算符返回 true;

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

仅由 EQName 组成的 ItemType 被解释为 AtomicOrUnionType。如果 deriveds-from( AT, AtomicOrUnionType ) 为真,则预期类型 AtomicOrUnionType 匹配实际类型为 AT 的原子值。

综合起来,效果是表达式3 instance of xs:positiveInteger返回 false(因为xs:integer不是从 派生的xs:positiveinteger)。

最后,当函数参数的预期类型是xs:positiveInteger,并且函数调用提供值 3 时,第 3.1.5.2 节中的函数转换规则开始发挥作用。这些允许从提供的值到所需类型的各种转换,但从 xs:integer 到 xs:positiveInteger 的“向下转换”不是其中之一。所以这是一个错误:

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

正如我所说,我不喜欢这些规则,并多次尝试改变它们。但它们是明确的,任何不遵循它们的产品都是不合格的。

于 2020-03-27T08:31:08.583 回答
1

https://www.w3.org/TR/xpath-31/#promotion指定允许的促销类型:

数字类型提升:

xs:float 类型的值(或通过限制从 xs:float 派生的任何类型)可以提升为 xs:double 类型。结果是与原始值相同的 xs:double 值。

xs:decimal 类型的值(或通过限制从 xs:decimal 派生的任何类型)可以提升为 xs:float 或 xs:double 类型之一。此提升的结果是通过将原始值转换为所需类型来创建的。这种提升可能会导致精度损失。

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

于 2020-03-27T08:28:10.890 回答
0

您可以将数字文字传递给MarkLogic1中的函数: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 :)

并且可以xdmp:type()用来报告返回的值是类型positiveInteger

xquery version "1.0-ml";
declare function local:pos-int($n as xs:positiveInteger) { $n };
xdmp:type(local:pos-int(1))
于 2020-03-27T00:29:42.220 回答