Почему числовой литерал c никогда не может иметь тип xs: positiveInteger в XQuery? - PullRequest
3 голосов
/ 27 марта 2020

Я заметил небольшие различия в том, как реализации XQuery обрабатывают (под) типы. В частности, обработка литеральных чисел в качестве входных данных для функций, для которых объявлен принятый тип ввода. Я наивно думал, что любой числовой литерал, который может быть преобразован в этот конкретный тип c цифра c, будет принят.

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 Spe c 2.5.5 Соответствие SequenceType или функции Xpath spe c 1.6.3 Atomi c Иерархия типов

Может ли кто-нибудь здесь пролить свет на то, почему Saxon 9.3.1 HE, BaseX 9.3.1 [Standalone] и eXist 5.3.0-SNAPSHOT ведут себя так?

Я только что пропустил часть в spe c, где определено, что литерал 1 приведен к xs: integer? xs: decimal, поскольку самый верхний тип имел бы больше смысла, но если разрешен один подтип, почему бы не go до конца?

- вот живая демонстрация

Ответы [ 3 ]

6 голосов
/ 27 марта 2020

Я думаю, что spe c в этой области очень прискорбно, но ясно: значение равно xs:positiveInteger, только если оно помечено как таковое, а не просто потому, что оно является (a) целым числом и (b) ) положительный В Рабочей группе XQuery велись долгие дискуссии с участием некоторых видных экспертов по системам типов языков программирования (таких как Фил Уодлер), и это решение было принято. Мне самому это не понравилось.

Где spe c говорит это? Определения в XDM spe c являются хорошим началом:

https://www.w3.org/TR/xpath-datamodel-31/#xs -типов

[Определение: значение atomi c равно значение в пространстве значений типа atomi c и помечено именем этого типа atomi c.]

[Определение: тип atomi c является примитивным простым типом или тип, полученный ограничением другого типа атома c.] (Типы, полученные списком или объединением, не являются атомами c.)

[Определение: простые примитивные типы - это типы, определенные в 2.1.1 Типы взято из XML Схема.]

Затем §3.1.1 в XQuery spe c говорит о числовых значениях c:

Значение цифра c литерал, не содержащий "." и ни один символ e или E не является атомом c значением типа xs: integer.

§3.18.1 дает правила для оператора "instance of":

Логический оператор instance of возвращает true, если значение его первого операнда соответствует SequenceType во втором операнде, в соответствии с правилами сопоставления SequenceType;

и §2.5.5.2 дают соответствующие правило соответствия SequenceType:

ItemType, состоящий просто из EQName, интерпретируется как AtomicOrUnionType. Ожидаемый тип AtomicOrUnionType соответствует значению атома c, фактический тип которого равен AT, если значение наследуется от (AT, AtomicOrUnionType) - true.

Взятые вместе, эффект заключается в том, что выражение 3 instance of xs:positiveInteger возвращает false (поскольку xs:integer не является производным от xs:positiveinteger).

Наконец, когда ожидаемый тип аргумента функции равен xs:positiveInteger, а вызов функции предоставляет значение 3, тогда правила преобразования функции в §3.1.5.2 вступают в игру. Они допускают различные преобразования из предоставленного значения в требуемый тип, но «понижающее преобразование» из xs: integer в xs: positiveInteger не является одним из них. Так что это ошибка:

Если после приведенных выше преобразований результирующее значение не соответствует ожидаемому типу в соответствии с правилами для SequenceType Matching, возникает ошибка типа [err: XPTY0004].

Как я уже сказал, мне не нравятся правила, и я неоднократно пытался их изменить. Но они понятны, и любой продукт, который им не следует, не соответствует.

1 голос
/ 27 марта 2020

https://www.w3.org/TR/xpath-31/#promotion указывает, какие типы поощрений разрешены:

Numeri c Типовые поощрения:

Значение типа xs: float (или любой тип, полученный ограничением из xs: float), может быть преобразован в тип xs: double. Результатом является значение xs: double, которое совпадает с исходным значением.

Значение типа xs: decimal (или любого типа, полученного путем ограничения из xs: decimal) может быть повышено до любого из типов. хз: поплавок или хз: двойной. Результат этого продвижения создается путем приведения исходного значения к требуемому типу. Такое продвижение может привести к потере точности.

Для других типов вы должны явно использовать конструктор, например local:int(xs:int(1)).

0 голосов
/ 27 марта 2020

Вы можете передать число c литерал 1 в функцию local:pos-int() в MarkLogi c:

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))
...