0

For example:

@FindBy(xpath = "//div[@id='panel']//span[@class='name']")
private WebElement panel;

I've got a panel element. Is it possible to get value of XPath that I init above?

I need a solution how can I return:

//div[@id='panel']//span[@class='name']

string in a test.

3 Answers 3

1

Unfortunately you can not. You can see the WebElement interface here.

The closest you can do is to call getAttribute and you could extract an ID or a specific class name.

However, you can create a wrapper over WebElement that stores the locator:

public class RefreshableWebElement implements WebElement {

    ...

    public RefreshableWebElement(Driver driver, By by) {
        this.driver = driver;
        this.by = by;
    }

    public WebElement getElement() {
        return driver.findElement(by);
    }

    public WebElement getLocator() {
        return by;
    }

}

Selenium's @FindBy annotation really takes control of the element initiation; if you want to have some control over it, you would have to drop @FindBy and implement its mechanisms yourself.

1

If this is really what you need you can obtain the value of foundBy field of the RemoteWebElement using Java Reflection API

Example code:

java.lang.reflect.Field field = panel.getClass().getDeclaredField("foundBy");
field.setAccessible(true);
String foundBy = field.get(element).toString();

But remember when you bypass Java encapsulation using reflection somewhere somehow a kitten dies so there should be a better way of implementing your requirement.

I don't like your XPath expression as well, according to XPath syntax

// Selects nodes in the document from the current node that match the selection no matter where they are

So you either need to do something like:

//div[@id='panel']//span[@class='name']

or use descendant axis like:

//div[@id='panel']/descendant::span[@class='name']

or just simplify it to

//span[@class='name']

More information:

0

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;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.