Skip to content

Commit

Permalink
Fix intersecting buckets in strange path expressions
Browse files Browse the repository at this point in the history
The bucket for the getNextSibling call in DomFacade for `following-sibling::node()[1][self::xxx]` is
not the same as the bucket in the `following-sibling::node()[self::xxx][1]` query
  • Loading branch information
DrRataplan committed Sep 7, 2023
1 parent 8948599 commit 3193daf
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 4 deletions.
20 changes: 16 additions & 4 deletions src/parsing/compileAstToExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,7 @@ function pathExpr(ast: IAST, compilationOptions: CompilationOptions) {
const children = astHelper.getChildren(step, '*');
const postFixExpressions: (['lookup', '*' | Expression] | ['predicate', Expression])[] = [];
let intersectingBucket: Bucket = null;
let hasSeenNullBucket = false;
for (const child of children) {
switch (child[0]) {
case 'lookup':
Expand All @@ -830,10 +831,21 @@ function pathExpr(ast: IAST, compilationOptions: CompilationOptions) {
childPredicate,
disallowUpdating(compilationOptions)
);
intersectingBucket = intersectBuckets(
intersectingBucket,
predicateExpression.getBucket()
);
if (!hasSeenNullBucket) {
const predicateBucket = predicateExpression.getBucket();
if (predicateBucket === null) {
// If we see a null bucket, we cannot use any future buckets
// anymore. This filter may have been position-aware For example:
// `following-sibling::node()[1][self::xxx]` is not the same as
// `following-sibling::node()[self::xxx][1]`.
hasSeenNullBucket = true;
} else {
intersectingBucket = intersectBuckets(
intersectingBucket,
predicateBucket
);
}
}
postFixExpressions.push(['predicate', predicateExpression]);
}
break;
Expand Down
6 changes: 6 additions & 0 deletions test/specs/parsing/getBucketForSelector.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,10 @@ describe('getBucketForSelector', () => {
it('returns the correct bucket for text expressions', () => {
assertBucketForSelector('self::text()', 'type-3');
});
it('returns the correct bucket if a filter is position-aware', () => {
// Note the axis does not make sense here. But this should work for following-sibling as well
assertBucketForSelector('self::node()[1][self::xxx]', null);
// The order is changed: this makes it not position-aware
assertBucketForSelector('self::node()[self::xxx][1]', 'name-xxx');
});
});

0 comments on commit 3193daf

Please sign in to comment.