【发布时间】:2016-09-14 02:27:38
【问题描述】:
是否可以返回 WebElement 的 xpath ?
【问题讨论】:
标签: webdriver
是否可以返回 WebElement 的 xpath ?
【问题讨论】:
标签: webdriver
不是直接来自 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 来自this post,已缩小到一行。它可能并不完美,但可以让你知道去哪里。大多数驱动程序都实现了JavascriptExecutor 接口,并具有在浏览器中执行Javascript 的能力。 executeScript 可以返回任何原始 JavaScript 类型、HTML 元素或任何前述内容的非嵌套列表。
Not all browsers support xpath the same way,所以在使用这些 xpath 选择元素时要小心。此外,并非所有浏览器都支持原生 xpath(cough IE cough),所以在这种情况下它是伪造的。
【讨论】:
如果 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);
}
【讨论】:
我会直接评论dflems'answer,但我没有这样做的声誉。
将整个 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。
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;
}
【讨论】: