eXist-db / exist

eXist Native XML Database and Application Platform
https://exist-db.org
GNU Lesser General Public License v2.1
423 stars 179 forks source link

[BUG] Broken "following" and "preceding" axes #3459

Open EfraimFeinstein opened 4 years ago

EfraimFeinstein commented 4 years ago

Describe the bug

The second XPath predicate as a filter when using the following axis give seems to be ignored, leading to incorrect XPath results. This code worked in eXist 4.7.1; It is failing in eXist 5.2.0.

Expected behavior

The second predicate would limit the results of the first. Test shown below.

To Reproduce

xquery version "3.1";

module namespace t="http://exist-db.org/xquery/test";

declare namespace test="http://exist-db.org/xquery/xqsuite";

declare 
    %test:arg("container", "<container><lvl1><value>1</value></lvl1><lvl1><value>2</value></lvl1><lvl1><value>3</value></lvl1></container>")
    %test:assertEmpty
    function t:show-error-following(
    $container as element()
    ) as element()? {
        let $context := $container/lvl1[2]
        return
            $context/following::lvl1[1][value='v']
};

declare 
    %test:arg("container", "<container><lvl1><value>1</value></lvl1><lvl1><value>2</value></lvl1><lvl1><value>3</value></lvl1></container>")
    %test:assertEmpty
    function t:show-error-preceding(
    $container as element()
    ) as element()? {
        let $context := $container/lvl1[2]
        return
            $context/preceding::lvl1[1][value='v']
};

declare 
    %test:arg("container", "<container><lvl1><value>1</value></lvl1><lvl1><value>2</value></lvl1><lvl1><value>3</value></lvl1></container>")
    %test:assertEmpty
    function t:self-works-fine(
    $container as element()
    ) as element()? {
        let $context := $container/lvl1[2]
        return
            $context/self::lvl1[1][value='v']
};

Context (please always complete the following information):

OS: Ubuntu 20.04 eXist: 5.2.0 Java: openjdk version "1.8.0_252" OpenJDK Runtime Environment (build 1.8.0_252-8u252-b09-1ubuntu1-b09) OpenJDK 64-Bit Server VM (build 25.252-b09, mixed mode)

Additional context

Installed via Jar installer

No.

joewiz commented 3 years ago

I can confirm @EfraimFeinstein's report and that this error is present in eXist 5.3.0-SNAPSHOT and earlier 5.x releases but not in 4.7.1. Here is a somewhat more readable version of the supplied test:

xquery version "3.1";

module namespace t="http://exist-db.org/xquery/test";

declare namespace test="http://exist-db.org/xquery/xqsuite";

declare variable $t:data := 
    <container>
        <lvl1>
            <value>1</value>
        </lvl1>
        <lvl1>
            <value>2</value>
        </lvl1>
        <lvl1>
            <value>3</value>
        </lvl1>
    </container>;

declare variable $t:context := $t:data/lvl1[2];

declare 
    %test:assertEmpty
function t:following(){
    $t:context/following::lvl1[1][value = "v"]
};

declare 
    %test:assertEmpty
function t:preceding() {
    $t:context/preceding::lvl1[1][value = "v"]
};

declare 
    %test:assertEmpty
function t:self() {
    $t:context/self::lvl1[1][value = "v"]
};

Results in 5.3.0-SNAPSHOT:

<testsuite package="http://exist-db.org/xquery/test" timestamp="2020-12-29T19:48:17.69-05:00"
    tests="3" failures="2" errors="0" pending="0" time="PT0.02S">
    <testcase name="following" class="t:following">
        <failure message="assertEmpty failed." type="failure-error-code-1"/>
        <output>
            <lvl1>
                <value>3</value>
            </lvl1>
        </output>
    </testcase>
    <testcase name="preceding" class="t:preceding">
        <failure message="assertEmpty failed." type="failure-error-code-1"/>
        <output>
            <lvl1>
                <value>1</value>
            </lvl1>
        </output>
    </testcase>
    <testcase name="self" class="t:self"/>
</testsuite>
mathias-goebel commented 3 years ago

basically you can test with every chain of predicates that contains a false() after the first one. related specs: https://www.w3.org/TR/2017/REC-xpath-31-20170321/#doc-xpath31-Predicate

xquery version "3.1";

let $node := <test>
    <one/>
    <two/>
    <two n="1"/>

    <nested>
        <two n="2"/>
    </nested>
    <two n="3"/>
</test>

return
    $node/one/following::two[1][false()]

i just checked 4.5.0 where i got an empty sequence. i can confirm the wrong behavior in 5.3.0. edit: wrong in this case it a returned node (<two/>)