Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I select all the columns first cells (tds) in Selenium webdriver?

I'm using Selenium 2.12. Using the WebDriver API, let's say I have a WebElement that represents a table (<table>). Using that element, how do I select all the td's in the first column? I'm assuming an xpath expression is in order here.

To better understand the table structure, if I get the HTML from my tableElement WebElement ...

String html = (String)((JavascriptExecutor)driver).executeScript("return arguments[0].innerHTML;", tableElt); 

I get the jumble below. The key thing to notice is that there are 6 tr's and 16 td's ...

<thead><tr><th colspan="1" class="GCSPOWVGE GCSPOWVEE GCSPOWVEF GCSPOWVFF"><div style="padding-left: 17px;position:relative;zoom:1;"><div style="left:0px;margin-top:-4px;position:absolute;top:50%;line-height:0px;"><img onload='this.__gwtLastUnhandledEvent="load";' src="http://localhost:9080/cme-productplus-web/productplus/clear.cache.gif" style="width: 11px; height: 7px; background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAHCAYAAADebrddAAAAiklEQVR42mNgwALyKrumFRf3iDAQAvmVXVVAxf/zKjq341WYV95hk1fZ+R+MK8C4HqtCkLW5FZ2PQYpyK6AaKjv/5VV1OmIozq3s3AFR0AXFUNMrO5/lV7WKI6yv6mxCksSGDyTU13Mw5JV2qeaWd54FWn0BRAMlLgPZl/NAuBKMz+dWdF0H2hwCAPwcZIjfOFLHAAAAAElFTkSuQmCC) no-repeat 0px 0px;" border="0"></div><div>GUID</div></div></th><th colspan="1" class="GCSPOWVGE GCSPOWVEF">Fung Ratio</th><th colspan="1" class="GCSPOWVGE GCSPOWVEF">Fung type</th><th colspan="1" class="GCSPOWVGE GCSPOWVEF">Fung Date Offset</th><th colspan="1" class="GCSPOWVGE GCSPOWVEF  GCSPOWVOE">Days To Retain</th></tr></thead><colgroup><col><col><col><col><col></colgroup><tbody><tr onclick="" class="GCSPOWVAE"><td class="GCSPOWVPD GCSPOWVBE GCSPOWVCE"><div style="outline:none;" tabindex="0">      DSSUAQR6IE6E    </div></td><td class="GCSPOWVPD GCSPOWVBE"><div style="outline:none;">      10      </div></td><td class="GCSPOWVPD GCSPOWVBE"><div style="outline:none;">              </div></td><td class="GCSPOWVPD GCSPOWVBE"><div style="outline:none;">      </div></td><td class="GCSPOWVPD GCSPOWVBE GCSPOWVME"><div style="outline:none;">            </div></td></tr><tr onclick="" class="GCSPOWVAF"><td class="GCSPOWVPD GCSPOWVBF GCSPOWVCE"><div style="outline:none;">      ETTUAQR6IE6E    </div></td><td class="GCSPOWVPD GCSPOWVBF"><div style="outline:none;">      30      </div></td><td class="GCSPOWVPD GCSPOWVBF"><div style="outline:none;">              </div></td><td class="GCSPOWVPD GCSPOWVBF"><div style="outline:none;">      </div></td><td class="GCSPOWVPD GCSPOWVBF GCSPOWVME"><div style="outline:none;">            </div></td></tr><tr onclick="" class="GCSPOWVAE"><td class="GCSPOWVPD GCSPOWVBE GCSPOWVCE"><div style="outline:none;">      FCCUAQR6IE6E    </div></td><td class="GCSPOWVPD GCSPOWVBE"><div style="outline:none;">      20      </div></td><td class="GCSPOWVPD GCSPOWVBE"><div style="outline:none;">              </div></td><td class="GCSPOWVPD GCSPOWVBE"><div style="outline:none;">      </div></td><td class="GCSPOWVPD GCSPOWVBE GCSPOWVME"><div style="outline:none;">            </div></td></tr></tbody><tbody style="display: none;"><tr><td colspan="5" align="center"><div><div style="width: 100%; height: 100%; padding: 0px; margin: 0px; display: none;"><div style="width: 100%; height: 100%; display: none;"></div></div><div style="width: 100%; height: 100%; padding: 0px; margin: 0px; display: none;"><div class="GCSPOWVPE" style="width: 100%; height: 100%; display: none;"><img class="gwt-Image" onload='this.__gwtLastUnhandledEvent="load";' src="http://localhost:9080/cme-productplus-web/productplus/clear.cache.gif" style="width: 43px; height: 11px; background: url(data:image/gif;base64,R0lGODlhKwALAPEAAP///0tKSqampktKSiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAKwALAAACMoSOCMuW2diD88UKG95W88uF4DaGWFmhZid93pq+pwxnLUnXh8ou+sSz+T64oCAyTBUAACH5BAkKAAAALAAAAAArAAsAAAI9xI4IyyAPYWOxmoTHrHzzmGHe94xkmJifyqFKQ0pwLLgHa82xrekkDrIBZRQab1jyfY7KTtPimixiUsevAAAh+QQJCgAAACwAAAAAKwALAAACPYSOCMswD2FjqZpqW9xv4g8KE7d54XmMpNSgqLoOpgvC60xjNonnyc7p+VKamKw1zDCMR8rp8pksYlKorgAAIfkECQoAAAAsAAAAACsACwAAAkCEjgjLltnYmJS6Bxt+sfq5ZUyoNJ9HHlEqdCfFrqn7DrE2m7Wdj/2y45FkQ13t5itKdshFExC8YCLOEBX6AhQAADsAAAAAAAAAAAA=) no-repeat 0px 0px;" border="0"></div></div></div></td></tr></tbody><tfoot style="display: none;"><tr><th colspan="5" class="GCSPOWVFE GCSPOWVDE  GCSPOWVNE"></th></tr></tfoot>

Sadly, both these expressions do not yield the correct results.

        // This returns zero td's
        final List<WebElement> tds = tableElt.findElements(By.xpath("/tr/td[1]"));

        ...

        // This returns 238 td's (I think that's everything in my document)
        final List<WebElement> tds = tableElt.findElements(By.xpath("//td[1]"));
like image 814
Dave Avatar asked Nov 30 '11 16:11

Dave


People also ask

How do you select the first element in a list in Selenium?

11) Using first-of-type CSS Selector in Selenium You can use “Tag:first-of-type”. It will select the first tag element.

How do I select all options in Selenium?

We can extract all the options in a dropdown in Selenium with the help of Select class which has the getOptions() method. This retrieves all the options on a Select tag and returns a list of web elements.


2 Answers

    // This returns 238 td's (I think that's everything in my document)               
    final List<WebElement> tds = tableElt.findElements(By.xpath("//td[1]"));

This is exactly as per thw XPath W3c Spec and is one of the most FAQ in XPath.

The precedence (priority) of the // pseudo-operator is less than that of the [] operator.

Therefore, //SomeName[1] selects all elements named SomeName that are the first SomeName child of their parent -- and there may be many such elements.

If you want to select the 1st SomeName element in the XML document, you need to explicitly override the default operator precedence using brackets:

(//SomeName)[1]

In this case you only want the first td descendant of a given element -- therefore in addition to the above correction, you must correct your expression to be relative -- not absolute. An absolute XPath expression (starting with / is always evaluated having as aditional context node the document node).

Use:

(.//td)[1]

If you need all td descendants of the current node selected, then use:

.//td

And even better:

.//descendant::td
like image 170
Dimitre Novatchev Avatar answered Sep 24 '22 18:09

Dimitre Novatchev


The exact expression to use depends on the actual structure of your document.

In the most general case -- selecting all of the first-column cells from a table -- you could use the following expression:

<path_to_table>//td[1]

For example, on this document:

<table>
    <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
        <td>4</td>
    </tr>
    <tr>
        <td>a</td>
        <td>b</td>
        <td>c</td>
        <td>d</td>
    </tr>
    <tr>
        <td>i</td>
        <td>ii</td>
        <td>iii</td>
        <td>iv</td>
    </tr>
</table>

This expression:

/table//td[1]

Gives:

<td>1</td>
<td>a</td>
<td>i</td>

Note that I'm using the descendant-or-self axis (//) because HTML tables allow optional grouping elements (e.g. <tbody>), which may or may not be there. However, this will include the first-column cells from nested tables, as well. Consider this input:

<table>
    <tr>
        <td>1</td>
        <td><table><td>test</td></table></td>
        <td>3</td>
        <td>4</td>
    </tr>
    <tr>
        <td>a</td>
        <td>b</td>
        <td>c</td>
        <td>d</td>
    </tr>
    <tr>
        <td>i</td>
        <td>ii</td>
        <td>iii</td>
        <td>iv</td>
    </tr>
</table>

The same expression from above returns:

<td>1</td>
<td>test</td>
<td>a</td>
<td>i</td>

If you know more about your specific table structure, then you can write a more specific expression. For example, on the previous input, this expression:

/table/tr/td[1]

...returns only cells from the outermost table:

<td>1</td>
<td>a</td>
<td>i</td>
like image 34
Wayne Avatar answered Sep 22 '22 18:09

Wayne