Re: XPath related query on extracting elements with webdriver 2 using Java

364 views
Skip to first unread message

darrell

unread,
Oct 15, 2012, 11:33:24 AM10/15/12
to webd...@googlegroups.com
Hi George,

Just some conventions you will notice for the group. A WebDriver is usually instantiated using driver, e.g.

    WebDriver driver = new FirefoxDriver();

So if someone posts:

    driver.findElements(...);

You'll know what they mean.

(a) The call to findElement will either find the element you are looking for or it will throw an exception (as you have found). The findElements (plural) will always return a List. So the slow way is to do:

    By by1 = By.xpath("/html/body/form/div[3]/div[2]/div[1]/h1/em");
    WebElement we1 = null;
    try {
        we1 = driver.findElement(by1);
    } catch(NoSuchElementException nsee) {
    }

The faster way is to use:

    List<WebElement> elements = driver.findElements(by1);
    int numElements = elements.size();
    if(numElements == 1) {
        we1 = elements.get(0);
    } else if(numElements > 1) {
        // too many elements
    } else {
        // no elements
    }

This will not wait for a timeout period and it will not throw an exception.

(b) The findElement and findElements methods do not allow for globbing or pattern matching. There is some support for wildcards in CSS and XPath. These would be defined by the CSS and XPath standards. You can use these in the locators you use for FindElement or findElements.

(c) If you want to find a specific tag with XPath parameters then use XPath. The By.tagName was just meant to find elements with a specific tagname. Nothing more.

(d) XPath is a standard outside the control of WebDriver. If the XPath standard allows for regex then you can use regex. As far as I know, this is not possible.

(e) Can you rely on anything in the structure? If I know the structure will be "find the DT tag with given text, go up one and down to the first DD with an IMG for a child, if the IMG exists" then I can use the XPath:

    String s = "Advertiser";
    List<WebElement> agencyLogoImages = driver.findElements(By.xpath("//dt[text()='" + s + "']/../dd/img[contains(@id,'AgencyLogo')]"));

If the image exists the size of agencyLogoImages will be 1.

One tip, look for patterns. From run to run or page to page you will see something change randomly. Other things will remain the same. You want to use the features available in CSS or XPath which allows you to filter on the things which remain the same. If there is too much maintenance on locators, it increases the risk the automation will be abandoned. For example, ctl00_ctl00_Content_Content_SrchResLst_rptResult_ctl04_lstTemplate_imgAgencyLogo is auto-generated by your framework. Many things will start with ctl00_ctl00_Content_Content_SrchResLst_rptResult_ctl04_lstTemplate_img for an id. More things will start with ctl00_ctl00_Content_Content_SrchResLst_rptResult_ctl04_lstTemplate. However, only the agency logo images id will end with imgAgencyLogo. So if you want to find the agency logo images, search for elements whose id ends with imgAgencyLogo.

Darrell

On Wednesday, 10 October 2012 06:47:29 UTC-7, George Jackson wrote:

Dear Selenium Webdriver 2 Experts,

I am new to this framework and need your advice on some XPath related questions on the following webpage XHTML snippet:

   1.    <dl class="cN-featDetails">
   2.         <dt class="propertytype">Property type</dt>
   3.         <dd id="ctl00_ctl00_Content_Content_SrchResLst_rptResult_ctl04_lstTemplate_ddPropertyType" class="propertytype type-house" title="Property type: House">House</dd>
   3a.        <!-- or  class="propertytype type-townhouse"--->
   4.         .......
   10. <div class="main-wrap">
   11.     <div class="s-prodDetails">
   12.         <a id="ctl00_ctl00_Content_Content_SrchResLst_rptResult_ctl04_lstTemplate_hypMainThumb" class="photo contain" href="/Property/For-Sale/House/LA/St Gabriel/?adid=2009938763">img id="ctl00_ctl00_Content_Content_SrchResLst_rptResult_ctl04_lstTemplate_imgMainThumb" title="44 Crown Street, St Gabriel" src="http://images.abc.com/img/2012814/2778/2009938763_1_PM.JPG?mod=121010-210000" alt="Main photo of 44 Crown Street, St Gabriel - More Details" style="border-width:0px;" /></a>
   13.         <div class="description">
   14.              <h4><span id="ctl00_ctl00_Content_Content_SrchResLst_rptResult_ctl04_lstTemplate_lblPrice">Offers Over $900,000 </span></h4>
   15.              <h5>SOLD BY WAISE YUSOFZAI</h5><p>CHARACTER FAMILY HOME... Filled with warmth and charm, is a very well maintained family home in a quiet level street. Be...</p>
   16.     </div>                                                                                                                                                                                                                                                                                                                       
   17.     <a id="ctl00_ctl00_Content_Content_SrchResLst_rptResult_ctl04_lstTemplate_hypMoreDetails" class="button" href="/Property/For-Sale/House/LA/St Gabriel/?adid=2009938763">More Details</a>
   18.     <dl id="ctl00_ctl00_Content_Content_SrchResLst_rptResult_ctl04_lstTemplate_dlAgent" class="agent">
   19.         <dt>Advertiser</dt>
   20.         <dd class="contain">                                      
   20a.        <!-- or class="" -->
   21.             <img id="ctl00_ctl00_Content_Content_SrchResLst_rptResult_ctl04_lstTemplate_imgAgencyLogo" title="Carmen Jones Realty" src="http://images.abc.com/img/Agencys/2778/searchlogo_2778.GIF" style="border-width:0px;" />                                                                                                                                                                                                                                                    
   22.         </dd>
   23.     </dl>
   24. </div>
  
   ( a ) How to test whether an element exist or not? e.g. either line 3 or 3a exist but not both. The findElement() method will cause an exception which is what I am trying avoid. Another option is
         use findElements() before checking whether its collection list result is empty or not. This approach seems to be a long winded way of doing it. Are there any other simpler way to validate the existence
         of an element without the risk of causing an exception? The following statements did not work or cause exception:
        
            WebElement resultsDiv = driver.findElement(By.xpath("/html/body/form/div[3]/div[2]/div[1]/h1/em"));
            // If results have been returned, the results are displayed in a drop down.
            if (resultsDiv.isDisplayed()) {
                break;
            }
         
   ( b ) Is there a simple way to validate the existence of either of the elements by incorporating boolean operator, and regex, as part of the findElement() or findElements()? This would significantly reduce
         the number of finds as well as simplifying the search.
        
   ( c ) Is it possible to use XPath syntax when searching Element by TagName. e.g. driver.findElement(By.tagName("/div[@class='report']/result"));
  
   ( d ) Is it possible to use regex in XPath search such as driver.findElement(By.xpath("//div[@class='main-wrap']/dl[@class='agent']/dd[@class='' OR @class='contain']")) for line 20 - 20a?
  
   ( e ) How to reference the immediate following node? e.g. Assuming the current node is <dt>Advertiser </dt> on line 19, how to lookup title of <img> which is under <dd>, where its class name
         can have a value of "contain" or nothing "". There could potentially be multiple <dd> tags within <dl> on line 18.
        
I have use XPath on XML document in the past but would like to expand the ability to locate elements within Webdriver 2.        
        
Any assistance would be very greatful.

Thanks a lot,

George                                                                                                                   

Reply all
Reply to author
Forward
0 new messages