This offered solution is only for xpath, and it only returns an absolute, not relative, xpath. It takes an already fetched WebElement and determines its xpath by recursively reading back to the root node. You call it by passing the WebElement and an empty string (""). I use this when I'm using Selenium to scrape a web page where I use a simple xpath to get all buttons, say, with "//button" into an array, then I can pass the elements one-by-one to the method to determine their individual xpaths. If your goal is to simply record ambiguous elements like I am in a data file so that they can later individually be retrieved with their direct xpaths, this might be useful.
public String generateXPATH(WebElement childElement, String current) {
String childTag = childElement.getTagName();
if (childTag.equals("html"))
return "/html" + current;
WebElement parentElement = childElement.findElement(By.xpath(".."));
List<WebElement> childrenElements = parentElement.findElements(By.xpath("*"));
int count = 0;
for (int i = 0; i < childrenElements.size(); i++) {
WebElement childrenElement = childrenElements.get(i);
String childrenElementTag = childrenElement.getTagName();
if (childTag.equals(childrenElementTag))
count++;
if (childElement.equals(childrenElement)) {
String subscript = "";
if (count > 1)
subscript = "[" + count + "]";
return generateXPATH(parentElement, "/" + childTag + subscript + current);
}
}
return null;
}