Backstory: I am working on a project where I needed to know the relative Xpath to a target Parent Node. I modified the answer provided
@James above to achieve what I wanted. Here's the code to get the relative XPath from a ParentNode (mainNode) to a child Node. Tags can be ignored when calling the function, it's used in the recursive calls to itself upon execution.
function getRealtiveXPathToChild(childNode, mainNode, Tags) {
const mainParent = mainNode.parentNode;
Tags = Tags ? Tags : [];
let currTag = childNode.tagName;
const currParent = childNode.parentNode;
if (currParent && mainParent !== currParent) {
var els = currParent.querySelectorAll(`:scope > ${currTag}`);
els.forEach((el, idx) => {
if (els.length > 1 && el === childNode) {
currTag += "[" + (idx + 1) + "]";
}
});
if(currTag) Tags.push(currTag);
return this.getRealtiveXPathToChild(currParent, mainNode, Tags);
}
return Tags.reverse().join("/");
}
Now, regarding your case and the example you provided, where you only have the relative xpath
and have no element nodes to work with. You wanted to get the absoute XPath
from those relative xpaths
that you already have. What you can do is to get the element from the relative xpath and then use that element to get its absolute xpath. Hope it helps.
/**
* Get The Element from the relative XPath
* Add double forward slashes at the beginning of the relative XPath
*/
const el = getElementByXpath(`//div[1]/p[1]`);
const absolutePath = getAbsoluteXPathFromNode(el);
function getElementByXpath(path, node) {
return document.evaluate(
path,
node ? node : document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
).singleNodeValue;
}
/**
* The function below is from another answer on this site.
* @ref : https://stackoverflow.com/questions/9197884/how-do-i-get-the-xpath-of-an-element-in-an-x-html-file
*/
function getAbsoluteXPathFromNode(node) {
var comp,
comps = [];
var parent = null;
var xpath = "";
var getPos = function (node) {
var position = 1,
curNode;
if (node.nodeType === Node.ATTRIBUTE_NODE) {
return null;
}
for (
curNode = node.previousSibling;
curNode;
curNode = curNode.previousSibling
) {
if (curNode.nodeName === node.nodeName) {
++position;
}
}
return position;
};
if (node instanceof Document) {
return "/";
}
for (
;
node && !(node instanceof Document);
node =
node.nodeType === Node.ATTRIBUTE_NODE
? node.ownerElement
: node.parentNode
) {
comp = comps[comps.length] = {};
/*eslint default-case: "error"*/
switch (node.nodeType) {
case Node.TEXT_NODE:
comp.name = "text()";
break;
case Node.ATTRIBUTE_NODE:
comp.name = "@" + node.nodeName;
break;
case Node.PROCESSING_INSTRUCTION_NODE:
comp.name = "processing-instruction()";
break;
case Node.COMMENT_NODE:
comp.name = "comment()";
break;
case Node.ELEMENT_NODE:
comp.name = node.nodeName;
break;
// No Default
}
comp.position = getPos(node);
}