data()
возвращает пустой элемент только потому, что тип аргумента node()
звучит для меня как ошибка. Какой процессор XQuery вы используете?
Звучит так, будто вам нужно успокоить статическую проверку типов, которую вы можете сделать с помощью выражения treat as
. Я не верю, что динамического теста с использованием instance of
будет достаточно.
Попробуйте это:
let $parameter := someNamespace:functionX() treat as element()
return local:myFunction($parameter)
Цитируя из 4-го издания «Большого опуса» Майкла Кея: «Оператор treat as
, по сути, говорит системе, что вы знаете, какой будет тип времени выполнения, и хотите, чтобы любая проверка была отложена до времени выполнения, потому что вы Вы уверены, что ваш код правильный. " (стр. 679)
ОБНОВЛЕНИЕ: Я думаю, что вышеупомянутое на самом деле неверно, поскольку treat as
это просто утверждение. Это не меняет аннотацию типа node()
, что означает, что это также неверное утверждение и не поможет вам. Хм ... Что я действительно хочу, это cast as
, но это работает только для атомарных типов. Я думаю, что я в тупике. Может быть, вы должны изменить движки XQuery. :-) Я сообщу, если подумаю о чем-то другом. Кроме того, мне любопытно узнать, подходит ли вам решение Димитра.
ОБНОВЛЕНИЕ № 2: Ранее я уже делал обратный ход. Могу ли я вернуться обратно? ;-) Теперь моя теория состоит в том, что treat as
будет работать на основе того факта, что node()
интерпретируется как объединение различных конкретных аннотаций типа узла, а не как сама аннотация типа во время выполнения (см. «Примечание» в разделе «Типы элементов» формальной семантики XQuery .) Во время выполнения аннотация типа будет 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, которые используют статическую проверку типов. (Извините за странное заключение; я чувствую, что заработал право. :-))
НОВЫЙ ОТВЕТ НА ОСНОВЕ ОБНОВЛЕННОЙ ИНФОРМАЦИИ : Похоже, что статическая проверка типа - это красная сельдь (большая жирная). Я полагаю, что вы на самом деле не имеете дело с элементом, а узлом документа , который является невидимым корневым узлом, который содержит элемент верхнего уровня (элемент документа) в модели данных XPath представление правильно сформированного XML-документа.
Таким образом, дерево моделируется следующим образом:
[document-node]
|
<docElement>
|
<subelement>
и не вот так:
<docElement>
|
<subelement>
Я предполагал, что вы проходите узел <docElement>
.Но если я прав, вы фактически проходите узел документа (его родитель).Поскольку узел документа невидим, его сериализация (то, что вы скопировали и вставили) неотличима от узла элемента, и различие было потеряно, когда вы вставили то, что теперь интерпретируется как пустой конструктор элемента в вашем XQuery.(Чтобы создать узел документа в XQuery, вам нужно обернуть конструктор элемента с помощью document{ ... }
.)
Тест instance of
не пройден, поскольку узел является не элементом, а документом-узел.(Это не node()
само по себе, потому что такой вещи нет; см. Объяснение выше.)
Кроме того, это объясняет, почему data()
возвращает пустое значение, когда вы пытались получить <subelement>
дочерний элемент дляузел документа (после ослабления типа аргумента функции до node()
).Первое представление дерева выше показывает, что <subelement>
является , а не дочерним узлом документа;таким образом, он возвращает пустую последовательность.
Теперь для решения.Перед передачей параметра (узла документа), получите его дочерний элемент (элемент документа), добавив /*
(или /element()
, что эквивалентно) следующим образом:
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...
};
Наконец, это выглядит как описание запроса eXist: функция get-data () совершенно непротиворечивас этим объяснением.В нем говорится: «Если это не двоичный документ, мы пытаемся проанализировать его как XML и вернуть document-node () ».(выделение добавлено)
Спасибо за приключение.Оказалось, что это обычная проблема XPath (осведомленность об узлах документов), но я узнал кое-что из нашего обхода о статической проверке типов.