是否可以返回 WebElement 的 xpath ?
8 回答
不是直接来自 WebDriver,但如果你真的需要,你可以伪造它:
public String getElementXPath(WebDriver driver, WebElement element) {
return (String)((JavascriptExecutor)driver).executeScript("gPt=function(c){if(c.id!==''){return'id(\"'+c.id+'\")'}if(c===document.body){return c.tagName}var a=0;var e=c.parentNode.childNodes;for(var b=0;b<e.length;b++){var d=e[b];if(d===c){return gPt(c.parentNode)+'/'+c.tagName+'['+(a+1)+']'}if(d.nodeType===1&&d.tagName===c.tagName){a++}}};return gPt(arguments[0]).toLowerCase();", element);
}
Javascript 来自这篇文章,已缩小到一行。它可能并不完美,但可以让你知道去哪里。大多数驱动程序都实现了该JavascriptExecutor
接口并具有在浏览器中执行 Javascript 的能力。executeScript
可以返回任何原始 JavaScript 类型、HTML 元素或上述任何内容的非嵌套列表。
并非所有浏览器都以相同的方式支持 xpath,因此在使用这些 xpath 选择元素时要小心。此外,并非所有浏览器都支持原生 xpath(咳嗽IE咳嗽),所以在这种情况下它是伪造的。
如果 WebElement 由 By.xpath: 在 Java 上找到:
public static String GetWebElementXpath(WebElement El) throws AssertionError{
if ((El instanceof WebElement)){
Object o = El;
String text = o.toString();
/* text is smth like this
[[FirefoxDriver: firefox on WINDOWS (9170d4a5-1554-4018-adac-f3f6385370c0)] -> xpath: //div[contains(@class,'forum-topic-preview')]//div[contains(@class,'small-human')]]
*/
text = text.substring( text.indexOf("xpath: ")+7,text.length()-1);
return text;
}else { Assert.fail("Argument is not an WebElement, his actual class is:"+El.getClass()); }
return "";
}
上述两个答案都存在同样的问题。通过使用.toLowerCase()
调用的函数返回完整的 XPath,任何包含带有大写字母的 id 的 XPath 都将不起作用。
示例://div[@id="deviceblock-1111"]
不适用于标签<div id="deviceBlock-1111">
但是,您可以只删除.toLowerCase()
返回的调用,但最终 XPath 看起来像这样://DIV[@id="deviceBlock-1111"]/DIV[2]/SELECT[1]/OPTION[5]
要解决此问题,请使用以下功能。
public String GetElementXPath(WebElement element, WebDriver driver)
{
return (String) ((JavascriptExecutor) driver).executeScript(
"getXPath=function(node)" +
"{" +
"if (node.id !== '')" +
"{" +
"return '//' + node.tagName.toLowerCase() + '[@id=\"' + node.id + '\"]'" +
"}" +
"if (node === document.body)" +
"{" +
"return node.tagName.toLowerCase()" +
"}" +
"var nodeCount = 0;" +
"var childNodes = node.parentNode.childNodes;" +
"for (var i=0; i<childNodes.length; i++)" +
"{" +
"var currentNode = childNodes[i];" +
"if (currentNode === node)" +
"{" +
"return getXPath(node.parentNode) +
'/' + node.tagName.toLowerCase() +
'[' + (nodeCount+1) + ']'" +
"}" +
"if (currentNode.nodeType === 1 && " +
"currentNode.tagName.toLowerCase() === node.tagName.toLowerCase())" +
"{" +
"nodeCount++" +
"}" +
"}" +
"};" +
"return getXPath(arguments[0]);", element);
}
这将从您的 WebElement 返回格式正确、唯一的 XPath。
//div[@id="deviceBlock-1111"]/div[2]/select[1]/option[5]
public String getElementXPath(WebDriver driver, WebElement element) {
String javaScript = "function getElementXPath(elt){" +
"var path = \"\";" +
"for (; elt && elt.nodeType == 1; elt = elt.parentNode){" +
"idx = getElementIdx(elt);" +
"xname = elt.tagName;" +
"if (idx > 1){" +
"xname += \"[\" + idx + \"]\";" +
"}" +
"path = \"/\" + xname + path;" +
"}" +
"return path;" +
"}" +
"function getElementIdx(elt){" +
"var count = 1;" +
"for (var sib = elt.previousSibling; sib ; sib = sib.previousSibling){" +
"if(sib.nodeType == 1 && sib.tagName == elt.tagName){" +
"count++;" +
"}" +
"}" +
"return count;" +
"}" +
"return getElementXPath(arguments[0]).toLowerCase();";
return (String)((JavascriptExecutor)driver).executeScript(javaScript, element);
}
将整个 xpath 转换为小写是可以的,除非 xpath 包含一个并非全部小写的 id 值。下面是 dflems 的 Javascript 的修改版本,但使用的是 Python 而不是 Java:
def get_xpath_from_element(driver, element):
return driver.execute_script("gPt=function(c){if(c.id!==''){return'id(\"'+c.id+'\")'}if(c===document.body){return c.tagName}var a=0;var e=c.parentNode.childNodes;for(var b=0;b<e.length;b++){var d=e[b];if(d===c){return gPt(c.parentNode)+'/'+c.tagName.toLowerCase()+'['+(a+1)+']'}if(d.nodeType===1&&d.tagName===c.tagName){a++}}};return gPt(arguments[0]);", element)
有一种方法可以在不使用 JavaScript 的情况下获取元素 XPath。
- 定义外部 XPath 的起点,例如 body 标记。
- 用 selenium 检查所有可能的内向标签
NoSuchElementException
。 - 检查
getText
生成的 XPath 列表。 - 赢
public static String getXPathFromElement(WebElement element) {
String elementDescription = element.toString();
return elementDescription.substring(elementDescription.lastIndexOf("-> ") + 3, elementDescription.lastIndexOf("]"));
}
Web 元素 toString() 如下所示:
'[[FirefoxDriver: WINDOWS 上的 firefox (ceb69f9f-bef4-455d-b626-ab439f195be6)] -> id: pageBeanfundDescription]'
我只是提取 id/xpath。
/**
* This method return By reference for the WebElement passed to it as a parameter.
* @param element
* @return
*/
public static By convertWebElementToByReference(WebElement element)
{
By byLocator = null;
String elementDescription = element.toString();
String elementTypeAndValue[] = (elementDescription.substring(elementDescription.lastIndexOf("-> ") + 3, elementDescription.lastIndexOf("]"))).split(":");
switch (elementTypeAndValue[0].trim())
{
case "id": byLocator = By.id(elementTypeAndValue[1].trim());
break;
case "xpath": byLocator = By.xpath(elementTypeAndValue[1].trim());
break;
case "link text": byLocator = By.linkText(elementTypeAndValue[1].trim());
break;
case "tag name": byLocator = By.tagName(elementTypeAndValue[1].trim());
break;
case "class name": byLocator = By.className(elementTypeAndValue[1].trim());
break;
case "partial link text": byLocator = By.partialLinkText(elementTypeAndValue[1].trim());
break;
case "name": byLocator = By.name(elementTypeAndValue[1].trim());
break;
case "css selector": byLocator = By.cssSelector(elementTypeAndValue[1].trim());
break;
default:
throw new RuntimeException("Invalid locator type: " + elementTypeAndValue[0].trim());
}
return byLocator;
}