Ось предка XQuery не работает, но явный XPath делает - PullRequest
0 голосов
/ 03 января 2012

Рассмотрим следующий XML фрагмент:

<doc>
    <chapter id="1">
        <item>
            <para>some text here</para>
        </item>
    </chapter>
</doc>

В XQuery у меня есть функция, которая должна делать некоторые вещи на основе главы предка данного "para "элемент, который передается как параметр, как показано в урезанном примере ниже:

declare function doSomething($para){
    let $chapter := $para/ancestor::chapter
    return "some stuff"
};

В этом примере $ chapter продолжает появляться пустым.Однако, если я напишу функцию, аналогичную следующей (т.е. без использования оси предка ), я получу желаемый элемент "chapter":

declare function doSomething($para){
    let $chapter := $para/../..
    return "some stuff"
};

Проблема в том, что яне может использовать явные пути, как в последнем примере, потому что XMl, который я буду искать, не гарантирует, что элемент "chapter" будет прародителем каждый раз.Это может быть прапрадедушка или прапрадедушка и т. Д., Как показано ниже:

<doc>
    <chapter id="1">
        <item>
            <subItem>
                <para>some text here</para>
            </subItem>
        </item>
    </chapter>
</doc>

Есть ли у кого-нибудь объяснения относительнопочему ось не работает, а явная XPath работает?Кроме того, у кого-нибудь есть какие-либо предложения о том, как решить эту проблему?

Спасибо.


РЕШЕНИЕ:

Тайна теперь разгадана.

Узел, о котором идет речь, был воссоздан в другой функции, что привело к удалению из него всей информации о его предке.К сожалению, предыдущий разработчик не задокументировал эту замечательную, маленькую функцию и стоил нам всем большого количества времени.

Итак, ось предка работала именно так, как и должна - она ​​просто применялась к обманчивому узлу.

Я благодарю всех вас за ваши усилия ответить на мои вопросы.

Ответы [ 4 ]

4 голосов
/ 03 января 2012

Ось предка работает нормально. Я подозреваю, что ваша проблема в пространствах имен. Пример, который вы показали и который я запускал (ниже), содержит XML без каких-либо пространств имен. Если у вашего XML есть пространство имен, вам нужно указать его в предке XPath , например: $para/ancestor:foo:chapter, где в этом случае prefix _foo_ is привязано к правильному пространству имен для элемента chapter.

let $doc := <doc>
    <chapter id="1">
        <item>
            <para>some text here</para>
        </item>
    </chapter>
</doc>

let $para := $doc//para
return $para/ancestor::chapter

РЕЗУЛЬТАТ:

<?xml version="1.0" encoding="UTF-8"?>
<chapter id="1">
  <item>
    <para>some text here</para>
  </item>
</chapter>
2 голосов
/ 04 января 2012

Эти вещи почти всегда сводятся к пространствам имен!В качестве доказательства того, что 100% пространства имен не являются проблемой, вы можете попробовать:

declare function local:doSomething($para) {
    let $chapter := $para/ancestor::*[local-name() = 'chapter']
    return $chapter
};
1 голос
/ 03 января 2012

Я подозреваю, что пространства имен тоже.Если $para/../.. работает, но $para/parent::item/parent::chapter оказывается пустым, то вы знаете, что это вопрос пространств имен.

Найдите объявление xmlns в верхней части вашего контента, например:

<doc xmlns="http://example.com">
  ...
</doc>

В вашем XQuery вам необходимо привязать это пространство имен к префиксу и использовать этот префикс в выражениях XQuery / XPath, например:

declare namespace my="http://example.com";
declare function doSomething($para){
  let $chapter := $para/ancestor::my:chapter
  return "some stuff"
};

Какой префикс вы используете, не имеет значения.Важно то, что URI пространства имен (http://example.com в приведенном выше примере) совпадает.

Имеет смысл, что ../.. выбирает нужный элемент, потому что .. - это сокращение от parent::node(), чтовыбирает родительский узел независимо от его имени (или пространства имен).Принимая во внимание, что ancestor::chapter будет выбирать только элементы <chapter>, которые не находятся в пространстве имен (если только вы не объявили пространство имен элемента по умолчанию, что обычно не является хорошей идеей в XQuery, поскольку оно влияет как на ваш ввод, так и на вывод).

1 голос
/ 03 января 2012

Это кажется мне удивительным;какую реализацию XQuery вы используете?С BaseX следующий запрос ...

declare function local:doSomething($para) {
    let $chapter := $para/ancestor::chapter
    return $chapter
};

let $xml :=
  <doc>
    <chapter id="1">
        <item>
            <para>some text here</para>
        </item>
    </chapter>
</doc>
return local:doSomething($xml//para)

... возвращает ...

<chapter id="1">
  <item>
    <para>some text here</para>
  </item>
</chapter>
...