Почему числовой литерал никогда не может иметь тип xs:positiveInteger в XQuery?

Я заметил тонкие различия в том, как реализации 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 :)

существующая база данных позволяет xs:long,xs:int, ... Saxon не позволяет.

Я не смог найти причину такого поведения в спецификации Xquery 2.5. 5 Сопоставление SequenceType и спецификации функций Xpath 1.6.3 Иерархия атомарных типов

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

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

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


person line-o    schedule 26.03.2020    source источник
comment
Синтаксис в вашем примере кода немного отличается. Вместо declare local:any function (... должно быть declare function local:any(....   -  person Joe Wicentowski    schedule 27.03.2020
comment
Я открыл проблему для существующего github.com/eXist-db/exist/issues/3330< /а>   -  person line-o    schedule 27.03.2020


Ответы (3)


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

Где спецификация это говорит? Определения в спецификации XDM — хорошее начало:

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

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

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

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

Затем в §3.1.1 спецификации XQuery говорится о числовых литералах:

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

§3.18.1 дает правила для оператора «экземпляр»:

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

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

ItemType, состоящий просто из EQName, интерпретируется как AtomicOrUnionType. Ожидаемый тип AtomicOrUnionType соответствует атомарному значению, фактический тип которого — 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, возникает ошибка типа [err:XPTY0004].

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

person Michael Kay    schedule 27.03.2020
comment
Спасибо за исчерпывающий ответ. Я был совершенно уверен, я просто пропустил спецификацию. - person line-o; 27.03.2020

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

person Martin Honnen    schedule 27.03.2020

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

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))
person Mads Hansen    schedule 27.03.2020
comment
Судя по ответам, данным @Micheal Kay и @Martin Honnen, это кажется несовместимым со спецификацией (как и поведение exists-db, разрешающее понижающие приведения к xs:long и его подтипам). - person line-o; 27.03.2020
comment
Интересно, позволяют ли эти продукты передавать десятичное значение 1.3 функции, которая ожидает xs:integer? Я спрашиваю, потому что кастинг позволяет это, в отличие от чистого нисходящего приведения, которое только проверяет соответствие значения без какого-либо преобразования. - person Michael Kay; 27.03.2020
comment
При выполнении со значением 1.3 выдается следующая ошибка приведения: [1.0-ml] XDMP-AS: (err:XPTY0004) $n as xs:positiveInteger -- Invalid coercion: 1.3 as xs:positiveInteger - person Mads Hansen; 29.03.2020