Skip to content

Commit

Permalink
[135] Use correct node positions on reverse axes
Browse files Browse the repository at this point in the history
  • Loading branch information
JLRishe committed Dec 16, 2023
1 parent 4b030c4 commit 834cae6
Show file tree
Hide file tree
Showing 4 changed files with 926 additions and 8 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"devDependencies": {
"@xmldom/xmldom": "^0.8.9",
"es-check": "^7.1.1",
"func-xml": "^0.0.10",
"mocha": "^9.0.2"
},
"typings": "./xpath.d.ts",
Expand Down
75 changes: 72 additions & 3 deletions test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const { allChildEls } = require('func-xml');
const xpath = require('./xpath.js');
const dom = require('@xmldom/xmldom').DOMParser;
const assert = require('assert');
const { strict: assert } = require('assert');

var xhtmlNs = 'http://www.w3.org/1999/xhtml';

Expand Down Expand Up @@ -461,6 +462,57 @@ describe('xpath', () => {
assert.equal('http://publisher', namespaces[4].nodeValue);
assert.equal('p', namespaces[4].localName);
});

it('should respect reverse axes', () => {
const doc = parseXml(`<book>
<chapter>Chapter 1</chapter>
<chapter>Chapter 2</chapter>
<chapter>Chapter 3</chapter>
<chapter>Chapter 4</chapter>
</book>`)

const [c1, c2, c3] = allChildEls(doc.documentElement);

assert.equal(
xpath.parse('/*/chapter[last()]/preceding-sibling::*[1]').evaluateString({ node: doc }),
'Chapter 3',
);

assert.equal(
xpath.parse('/*/chapter[last()]/preceding-sibling::*[2]').evaluateString({ node: doc }),
'Chapter 2',
);

assert.equal(
xpath.parse('/*/chapter[last()]/preceding-sibling::*[3]').evaluateString({ node: doc }),
'Chapter 1',
);

assert.equal(
xpath.parse('/*/chapter[last()]/preceding-sibling::*[4]').evaluateString({ node: doc }),
'',
);

assert.equal(
xpath.parse('/*/chapter[last()]/preceding-sibling::*[last()]').evaluateString({ node: doc }),
'Chapter 1',
);

assert.equal(
xpath.parse('/*/chapter[last()]/preceding::chapter[last()]').evaluateString({ node: doc }),
'Chapter 1',
);

assert.equal(
xpath.parse('/*/chapter[last()]/preceding::*[position() = 1]').evaluateString({ node: doc }),
'Chapter 3',
);

assert.equal(
xpath.parse('/*/chapter[last()]/preceding::*[. != "Chapter 3"][1]').evaluateString({ node: doc }),
'Chapter 2',
);
});
});

describe('string()', () => {
Expand Down Expand Up @@ -1046,18 +1098,35 @@ describe('xpath', () => {

assert.strictEqual('Heyy', translated);

var characters = parseXml('<characters><character>Harry</character><character>Ron</character><character>Hermione</character></characters>');
var characters = parseXml(`<characters>
<character>Harry</character>
<character>Ron</character>
<character>Hermione</character>
</characters>`);

var firstTwo = xpath.parse('/characters/character[position() <= 2]').select({ node: characters });

assert.strictEqual(2, firstTwo.length);
assert.strictEqual('Harry', firstTwo[0].textContent);
assert.strictEqual('Ron', firstTwo[1].textContent);

var last = xpath.parse('/characters/character[last()]').select({ node: characters });
const last = xpath.parse('/characters/character[last()]').select({ node: characters });

assert.strictEqual(1, last.length);
assert.strictEqual('Hermione', last[0].textContent);

const lastPrefiltered = xpath.parse('/characters/character[. != "Hermione"][last()]').select({ node: characters });

assert.strictEqual(1, lastPrefiltered.length);
assert.strictEqual('Ron', lastPrefiltered[0].textContent);

const lastStrict = xpath.parse('/characters/character[last() = 3]').select({ node: characters, });

assert.equal(3, lastStrict.length);

const lastStrictMiss = xpath.parse('/characters/character[last() = 2]').select({ node: characters, });

assert.equal(0, lastStrictMiss.length);
});
});

Expand Down
24 changes: 19 additions & 5 deletions xpath.js
Original file line number Diff line number Diff line change
Expand Up @@ -1794,7 +1794,7 @@ var xpath = (typeof exports === 'undefined') ? {} : exports;
return node;
}

PathExpr.applyPredicates = function (predicates, c, nodes) {
var applyPredicates = function (predicates, c, nodes, reverse) {
if (predicates.length === 0) {
return nodes;
}
Expand All @@ -1815,7 +1815,7 @@ var xpath = (typeof exports === 'undefined') ? {} : exports;
inNodes
);
},
sortNodes(nodes),
sortNodes(nodes, reverse),
predicates
);
};
Expand Down Expand Up @@ -2094,10 +2094,11 @@ var xpath = (typeof exports === 'undefined') ? {} : exports;
};

function applyStepWithPredicates(step, xpc, node) {
return PathExpr.applyPredicates(
return applyPredicates(
step.predicates,
xpc,
PathExpr.applyStep(step, xpc, node)
PathExpr.applyStep(step, xpc, node),
includes(REVERSE_AXES, step.axis)
);
}

Expand Down Expand Up @@ -2134,7 +2135,12 @@ var xpath = (typeof exports === 'undefined') ? {} : exports;
}

return {
nodes: PathExpr.applyPredicates(this.filterPredicates || [], xpc, ns.toUnsortedArray())
nodes: applyPredicates(
this.filterPredicates || [],
xpc,
ns.toUnsortedArray(),
false // reverse
)
};
};

Expand Down Expand Up @@ -2314,6 +2320,14 @@ var xpath = (typeof exports === 'undefined') ? {} : exports;
[Step.SELF, 'self']
]);

var REVERSE_AXES = [
Step.ANCESTOR,
Step.ANCESTORORSELF,
Step.PARENT,
Step.PRECEDING,
Step.PRECEDINGSIBLING
];

// NodeTest //////////////////////////////////////////////////////////////////

NodeTest.prototype = new Object();
Expand Down
Loading

0 comments on commit 834cae6

Please sign in to comment.