可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have a table with 9 rows and 6 columns in my webpage. I want to search for a text "MakeGoodDisabled-Programwise_09_44_38_461(n)" and get the xpath of the cell. I have used the following but it fails because it is not able to find the text on the page. Can you please help? I am using Selenium Webdriver Junit to code this.
List < WebElement > links = driver.findElements(By.tagName("td"));
Iterator < WebElement > itr = links.iterator();
while (itr.hasNext()) {
String test = itr.next().getText();
if (test.equals("MakeGoodDisabled-Programwise_09_44_38_461(n)")) {
String xpath = driver.findElement(By.name(test)).getAttribute("xpath");
System.out.println(xpath);
}
}
回答1:
My intention is to find a text in a table and get the corresponding next column value in
the same row. I thought that I will replace the column number found by fetching the xpath with
the column number I want. is there a better way to do it
Of course there's a way. Here's one possible solution.
Get all the rows:
While (iterate over row)
While(Iterate over column)
if(column.Text=='YOUR_MATCH'){
int voila=column.Index
}
}
}
Now you can simply move to that particular index for the other rows; or you could use xpath like .../tr/td[voila]
to retrieve all cells for that particular column.
I've written an approach, please don't take to be real-working-code!
回答2:
You can also use this to crawl up and generate the xpath:
Call the method below with
generateXPATH(element, "");
The output will be something like:
/html[1]/body[1]/div[5]/div[1]/div[2]/div[1]/div[1]/div[1]/div[1]/div[1]/div[1]/form[1]/div[2]/div[1]/input[2]
METHOD
private String generateXPATH(WebElement childElement, String current) {
String childTag = childElement.getTagName();
if(childTag.equals("html")) {
return "/html[1]"+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)) {
return generateXPATH(parentElement, "/" + childTag + "[" + count + "]"+current);
}
}
return null;
}
回答3:
The question which you asked does not make any sense to me. I guess there might be a strong reason for you to 'want to do it' !
Your line of code
String xpath = driver.findElement(By.name(test)).getAttribute("xpath");
will not return anything because there is no attribute 'xpath' in html elements. Please get your basics clear on to what xpath means??
if i have an html element as shown below
<input name = "username" value = "Name" readonly ="readonly">
i can get the values of attribute by using
driver.findElement(By.name("username").getAttribute("value"); // returns 'Name'
This will give me value of 'value' attribute
or
driver.findElement(By.name("username").getAttribute("readonly"); // returns 'readonly'
same as above !
回答4:
The XPath of an element is not a definitive value. An element can be found by many XPaths.
You cannot use Webdriver to extract an XPath and even if you could, it is unlikely to be the most efficient or sensible one, that can only be defined by the automator.
回答5:
You can generate xpaths with JavaScript:
function getPathTo(element) {
// only generate xpaths for elements which contain a particular text:
if (element.innerText == "MakeGoodDisabled-Programwise_09_44_38_461(n)") {
// use id to produce relative paths rather than absolute, whenever possible
if ((element.id !== '') && (element.id != 'undefined')) {
return 'id(\"' + element.id + '\")';
}
// stop looping when you get to the body tag
if (element === document.body) {
return element.tagName;
}
// calculate position among siblings
var ix = 0;
var siblings = element.parentNode.childNodes;
for (var i = 0; i < siblings.length; i++) {
var sibling = siblings[i];
if (sibling === element) {
return getPathTo(element.parentNode) + '/' + element.tagName + '[' + (ix + 1) + ']';
}
if (sibling.nodeType === 1 && sibling.tagName === element.tagName) {
ix++;
}
}
}
}
// put all matching xpaths in an array
var allXPaths = [];
// if you know the particular tag you are looking for, replace * below to optimize
var allTags = document.getElementsByTagName('*');
for (i = 0; i < allTags.length; i++) {
if ((getPathTo(allTags[i]).indexOf('/HEAD') == -1) && (getPathTo(allTags[i]).indexOf('undefined') == -1)) {
allXPaths.push(getPathTo(allTags[i]));
console.log(getPathTo(allTags[i]));
}
}
return allXPaths;
If you put that JavaScript in a String called getXPaths
then in Java, you can execute it like this:
ArrayList<String> xpaths = (ArrayList<String>) js.executeScript(getXPaths);
It returns an array rather than a String, because if your page happens to have fewer or more elements with matching tagname/innerText, You'll want to know. You can tell by the size of the array.
回答6:
JavaScript fnction's to generate XPath
XPath/locator is a way of addressing an element by navigating through the Tree structure.
Absolute XPath (/): /html/body/div[5]/div[4]
WebElement XPath:
function WebElement_XPath(element) {
if (element.tagName == 'HTML') return '/html';
if (element===document.body) return '/html/body';
// calculate position among siblings
var position = 0;
// Gets all siblings of that element.
var siblings = element.parentNode.childNodes;
for (var i = 0; i < siblings.length; i++) {
var sibling = siblings[i];
// Check Siblink with our element if match then recursively call for its parent element.
if (sibling === element) return WebElement_XPath(element.parentNode)+'/'+element.tagName+'['+(position+1)+']';
// if it is a siblink & element-node then only increments position.
var type = sibling.nodeType;
if (type === 1 && sibling.tagName === element.tagName) position++;
}
}
MouseEvent XPath:
var eventXPath = '';
function MouseEvent_XPath(e) {
event = e.target || e.srcElement ||e.originalTarget;
for ( var xpathEle = ''; event && event.nodeType == 1; event = event.parentNode ) {
if ( event.tagName == 'HTML' || event.tagName == 'html' ) {
eventXPath = '//html'+xpathEle; break;
}
if ( event.tagName == 'BODY' || event.tagName == 'body' ) {
eventXPath = '//html/body'+xpathEle; break;
}
// calculate position among siblings
var position = 0;
// Gets all siblings of that event.
var siblings = event.parentNode.children;
for (var i = 0; i < siblings.length; i++) {
var sibling = siblings[i];
// Check Sibling with our event if match then recursively call for its parent event.
if (sibling === event) xpathEle = "/"+event.tagName+'['+(position+1)+']'+xpathEle;
// if it is a sibling with same tagName then only increments position.
if (sibling.tagName === event.tagName) position++;
}
}
}
Relative xpath (//): //div[@id=’social-media’]/ul/li[3]/a
//Element.TagName[@id="idvalue" and @class="classValue" and text()="innerHTML data"]
OR you can use .(dot), . is an alias for text(), [.="innerHTML data"] if you know the content you are looking for is somewhere inside the specified tag, you can use this
Example run in console:
var xpath = "//div[@id='answer-32201731' and @data-answerid='32201731']";
var element = document.evaluate(xpath, window.document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ).singleNodeValue;
element.style.setProperty( 'outline', "3px solid blue","important");
回答7:
Assuming you have an attribute on your element with the name "xpath" you could do the following:
WebElement yourElement = driver.findElement(By.xpath("//td[contains(text(),'MakeGoodDisabled-Programwise_09_44_38_461(n)')]");
String xpathAttributeValue = targetButton.getAttribute("xpath");
Though by the sounds of it you are trying to achieve something else here you have not shared with us yet. Do you want selenium to create an xpath for you? It can't.
回答8:
Almost the same situation to me:
I have an element in the table, but I don't know in which column it's located (like some username across all the usernames). I need to find particular string with username and click "activate" button just for this user. (the username text locates in the 2nd column which is td[2] and the button locates in the 5th column which is td[5]). So I need to run all columns one by one to find the user and then click it's button:
for (int iter = 1;; iter++) {
try {
if (iter == 1) {
if ((username).equals(driver.findElement(By.xpath("/html/body/div[3]/div[4]/div/form/table/tbody/tr/td[2]/a")).getText())) {
driver.findElement(By.xpath("/html/body/div[3]/div[4]/div/form/table/tbody/tr/td[5]/a")).click();
break;
}
}
} catch (Error e) {}
try {
if (iter > 1) {
if ((username).equals(driver.findElement(By.xpath("/html/body/div[3]/div[4]/div/form/table/tbody/tr[" + iter + "]/td[2]/a")).getText())) {
driver.findElement(By.xpath("/html/body/div[3]/div[4]/div/form/table/tbody/tr[" + iter + "]/td[5]/a")).click();
break;
}
}
} catch (Error e) {}
}
}
回答9:
Before iterating, use this class. Then, when you findXPATHIDFromWebElement
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
public class XPATHDriverWrapper {
Map xpathIDToWebElementMap = new LinkedHashMap();
Map webElementToXPATHIDMap = new LinkedHashMap();
public XPATHDriverWrapper(WebDriver driver){
WebElement htmlElement = driver.findElement(By.xpath("/html"));
iterateThroughChildren(htmlElement, "/html");
}
private void iterateThroughChildren(WebElement parentElement, String parentXPATH) {
Map siblingCountMap = new LinkedHashMap();
List childrenElements = parentElement.findElements(By.xpath(parentXPATH+"/*"));
for(int i=0;i<childrenElements.size(); i++) {
WebElement childElement = childrenElements.get(i);
String childTag = childElement.getTagName();
String childXPATH = constructXPATH(parentXPATH, siblingCountMap, childTag);
xpathIDToWebElementMap.put(childXPATH, childElement);
webElementToXPATHIDMap.put(childElement, childXPATH);
iterateThroughChildren(childElement, childXPATH);
// System.out.println("childXPATH:"+childXPATH);
}
}
public WebElement findWebElementFromXPATHID(String xpathID) {
return xpathIDToWebElementMap.get(xpathID);
}
public String findXPATHIDFromWebElement(WebElement webElement) {
return webElementToXPATHIDMap.get(webElement);
}
private String constructXPATH(String parentXPATH,
Map siblingCountMap, String childTag) {
Integer count = siblingCountMap.get(childTag);
if(count == null) {
count = 1;
} else {
count = count + 1;
}
siblingCountMap.put(childTag, count);
String childXPATH = parentXPATH + "/" + childTag + "[" + count + "]";
return childXPATH;
}
}
Another wrapper class to generate ids from Document is posted at: http://scottizu.wordpress.com/2014/05/12/generating-unique-ids-for-webelements-via-xpath/
回答10:
I think their is not any special function available for getting the xpath of searched element. For this, First you need to find the element manually then get the xpath through getXpath functions.
回答11:
My java method to get absolute xpath:
public static String getXpath(WebElement element){
int n = element.findElements(By.xpath("./ancestor::*")).size();
String path = "";
WebElement current = element;
for(int i = n; i > 0; i--){
String tag = current.getTagName();
int lvl = current.findElements(By.xpath("./preceding-sibling::" + tag)).size() + 1;
path = String.format("/%s[%d]%s", tag, lvl, path);
current = current.findElement(By.xpath("./parent::*"));
}
return "/" + current.getTagName() + path;
}
and for relative xpath (this was first :) ):
public static String getXpath(WebElement self, WebElement ancestor){
int a = ancestor.findElements(By.xpath("./ancestor::*")).size();
int s = self.findElements(By.xpath("./ancestor::*")).size();
String path = "";
WebElement current = self;
for(int i = s - a; i > 0; i--){
String tag = current.getTagName();
int lvl = current.findElements(By.xpath("./preceding-sibling::" + tag)).size() + 1;
path = String.format("/%s[%d]%s", tag, lvl, path);
current = current.findElement(By.xpath("./parent::*"));
}
return path;
}