forked from dequelabs/axe-core
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathget-xpath.js
More file actions
84 lines (78 loc) · 2.39 KB
/
Copy pathget-xpath.js
File metadata and controls
84 lines (78 loc) · 2.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import escapeSelector from './escape-selector';
function getXPathArray(node, path) {
let sibling, count;
// Gets an XPath for an element which describes its hierarchical location.
if (!node) {
return [];
}
if (!path && node.nodeType === 9) {
// special case for when we are called and give the document itself as the starting node
path = [
{
str: 'html'
}
];
return path;
}
path = path || [];
if (node.parentNode && node.parentNode !== node) {
path = getXPathArray(node.parentNode, path);
}
if (node.previousSibling) {
count = 1;
sibling = node.previousSibling;
do {
if (sibling.nodeType === 1 && sibling.nodeName === node.nodeName) {
count++;
}
sibling = sibling.previousSibling;
} while (sibling);
if (count === 1) {
count = null;
}
} else if (node.nextSibling) {
sibling = node.nextSibling;
do {
if (sibling.nodeType === 1 && sibling.nodeName === node.nodeName) {
count = 1;
sibling = null;
} else {
count = null;
sibling = sibling.previousSibling;
}
} while (sibling);
}
if (node.nodeType === 1) {
const element = {};
element.str = node.nodeName.toLowerCase();
// add the id and the count so we can construct robust versions of the xpath
const id = node.getAttribute && escapeSelector(node.getAttribute('id'));
if (id && node.ownerDocument.querySelectorAll('#' + id).length === 1) {
element.id = node.getAttribute('id');
}
if (count > 1) {
element.count = count;
}
path.push(element);
}
return path;
}
// Robust is intended to allow xpaths to be robust to changes in the HTML structure of the page
// This means always use the id when present
// Non robust means always use the count (i.e. the exact position of the element)
// Ironically this is a bit of a misnomer because in very, very dynamic pages (e.g. where ids are generated on the fly)
// the non-ribust Xpaths will work whereas the robust ones will not work
function xpathToString(xpathArray) {
return xpathArray.reduce((str, elm) => {
if (elm.id) {
return `//${elm.str}[@id='${elm.id}']`;
} else {
return str + `/${elm.str}` + (elm.count > 0 ? `[${elm.count}]` : '');
}
}, '');
}
function getXpath(node) {
const xpathArray = getXPathArray(node);
return xpathToString(xpathArray);
}
export default getXpath;