fix: xpath queries should be atomic (#11101)
This commit is contained in:
parent
8324c16348
commit
6098bab2ba
@ -14,7 +14,11 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {QueryHandler, type QuerySelectorAll} from './QueryHandler.js';
|
import {
|
||||||
|
QueryHandler,
|
||||||
|
type QuerySelectorAll,
|
||||||
|
type QuerySelector,
|
||||||
|
} from './QueryHandler.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
@ -27,4 +31,15 @@ export class XPathQueryHandler extends QueryHandler {
|
|||||||
) => {
|
) => {
|
||||||
return xpathQuerySelectorAll(element, selector);
|
return xpathQuerySelectorAll(element, selector);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static override querySelector: QuerySelector = (
|
||||||
|
element: Node,
|
||||||
|
selector: string,
|
||||||
|
{xpathQuerySelectorAll}
|
||||||
|
) => {
|
||||||
|
for (const result of xpathQuerySelectorAll(element, selector, 1)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,8 @@
|
|||||||
*/
|
*/
|
||||||
export const xpathQuerySelectorAll = function* (
|
export const xpathQuerySelectorAll = function* (
|
||||||
root: Node,
|
root: Node,
|
||||||
selector: string
|
selector: string,
|
||||||
|
maxResults = -1
|
||||||
): Iterable<Node> {
|
): Iterable<Node> {
|
||||||
const doc = root.ownerDocument || document;
|
const doc = root.ownerDocument || document;
|
||||||
const iterator = doc.evaluate(
|
const iterator = doc.evaluate(
|
||||||
@ -28,8 +29,21 @@ export const xpathQuerySelectorAll = function* (
|
|||||||
null,
|
null,
|
||||||
XPathResult.ORDERED_NODE_ITERATOR_TYPE
|
XPathResult.ORDERED_NODE_ITERATOR_TYPE
|
||||||
);
|
);
|
||||||
|
const items = [];
|
||||||
let item;
|
let item;
|
||||||
|
|
||||||
|
// Read all results upfront to avoid
|
||||||
|
// https://stackoverflow.com/questions/48235278/xpath-error-the-document-has-mutated-since-the-result-was-returned.
|
||||||
while ((item = iterator.iterateNext())) {
|
while ((item = iterator.iterateNext())) {
|
||||||
yield item;
|
items.push(item);
|
||||||
|
if (maxResults && items.length === maxResults) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < items.length; i++) {
|
||||||
|
item = items[i];
|
||||||
|
yield item as Node;
|
||||||
|
delete items[i];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user