Glen Pierce
Glen Pierce

Reputation: 4801

How to find the child elements of a specific WebElement (which I don't know the xpath to)

I have an arbitrary number of tiles that have a unique class name. One of them has a unique title so I'm trying to grab that one specifically. Once I've done that, I want a reference to child element rather deep in its structure.

Does the "tile." part of tile.findElement() do anything for me here? I want to be specifically using an xpath relative to tile.

public WebElement getArticleTileByTitle(String title){
        By xpath = By.xpath(".//div[contains(., '" + title + "') or @title='" + title +  "']");
        List<WebElement> tiles = findPresentElements(By.className("articleTile"));
        for(WebElement tile : tiles){
            if(isElementPresent(tile, xpath))
                return tile;
        }
        return null;
    }

public boolean articleTileImageIsVisible(WebElement tile){
    WebElement background = tile.findElement(By.xpath("/*[2]/*[2]/*[1]/*[3]")); //This throws NoSuchElementException: no such element: Unable to locate element: {"method":"xpath","selector":"/*[2]/*[2]/*[1]/*[3]"}
    //figure out stuff about background
}

I know that background is of type img so I've tried

tile.findElement(By.xpath("./img/*[2]/*[2]/*[1]/*[3]"));
tile.findElement(By.xpath("./*/*[2]/*[2]/*[1]/*[3]"));
tile.findElement(By.xpath(".//*/*[2]/*[2]/*[1]/*[3]"));
tile.findElement(By.xpath("./*/*[2]/*[2]/*[1]/*[3]"));

Never the less, I keep getting variations on NoSuchElementException: no such element: Unable to locate element: {"method":"xpath","selector":"/[2]/[2]/[1]/[3]"} and That's not a valid xpath.

This question is very similar to Selenium 2 - Can findElement(By.xpath) be scoped to a particular element? but people seem to have either misinterpreted it or my use case is different.

Upvotes: 7

Views: 36528

Answers (2)

SiKing
SiKing

Reputation: 10329

The API documentation for findElements() says:

When using xpath be aware that webdriver follows standard conventions: a search prefixed with "//" will search the entire document, not just the children of this current node. Use ".//" to limit your search to the children of this WebElement.

Same rules apply to findElement() (the singular form). So you should be able to do something like:

WebElement foo = driver.findElement(By.xpath("//*[@title='" + title + "']"));
WebElement bar = foo.findElement(By.xpath(".//img"));

The leading dot in the second xpath makes all the difference, as it will search only for child elements of foo.

Upvotes: 25

STG
STG

Reputation: 113

Topic with similar question! - XPath to get all child nodes (elements, comments, and text) without parent

this part from that topic can interest you.

child::* selects all element children of the context node

child::text() selects all text node children of the context node

child::node() selects all the children of the context node, whatever their node type

We can identify the child nodes from the parent, by localizing it with the parent and then passing ( ./child::*) as a parameter to the findElements(By.xpath(""))

var childs = parent.findElements(By.xpath("./child::*"));

then in your code filter/process them...

Upvotes: 2

Related Questions