Click on the first web page item that matches an XPath

There have been couple of recent posts asking about using KM to click on particular elements on web pages.

Here is a generic macro which clicks on the first item (in Safari or Chrome) which matches an XPath expression in a KM variable.

(with the path //*[@id="search-button"] for example, it will just click on the Search button on this page.

Click the first Web element that matches an XPath.kmmacros (4.8 KB)

XPath queries work in Safari and Chrome.
One way of getting the XPath to an element (for use in either browser) is to use Chrome's Copy As Xpath command:

  1. Ctrl-click the clickable element of interest in Chrome
  2. Choose Inspect Element
  3. Select the relevant HTML element (typically an <a> element)
  4. Ctrl-click again and choose Copy as XPath
  5. Paste into the value field of the macro's Set Variable action

The .js code in the Execute JavaScript in Safari|Chrome actions is the same:

It:

  • Retrieves the kmvar.xPath variable from the browser document object
  • assumes that its value is a tested XPath expression, and passes it to the document.evaluate() function
  • clicks the first matching element on the front page in the browser
(function (strPath) {
    (function (e) {
        if (e.fireEvent) e.fireEvent('onclick');
        else {
            var o = document.createEvent('Events');
            o.initEvent('click', true, false);
            e.dispatchEvent(o);
        }
    })(
        document.evaluate(
            strPath, document, null, 0, null
        ).iterateNext()
    );
})(document.kmvar.xPath);
4 Likes

Thanks for this. Big help.

Now generalised as a custom plugin at:

1 Like

Thanks for sharing this approach. It definitely helped put me on the right track to using XPaths.

Unfortunately, your JavaScript doesn't work properly for me when used to click on the "cancel" link to a KM Forum reply or new topic:

  • It does click on the link
  • But then it causes the popup button "Yes, abandon" to be closed without clicking.

Here is the XPath that I used:
//*[@id="reply-control"]/div[2]/div[3]/div/div[3]/a

However, I found this simple script to work very well:

clickOnLink(document.kmvar.xPath);

function clickOnLink (pXPathStr) {

  var elemFound =  document.evaluate(
      pXPathStr, document, null, 0, null
    ).iterateNext();
    
  if (elemFound) {
    elemFound.click();
  }
  else {
    alert('Element NOT FOUND for XPath:\n' + pXPathStr);
  }

};

I don't really understand the purpose of the function(e) in your script, but I don't seem to need it.

2 Likes

5 posts were split to a new topic: How Do I Automate Fill of GMail Compose Form?

Thanks @ComplexPoint, I worked with JMichaelTX on an xPath statement and couldn't get it to work. Reading through all the posts I tried your JavaScript and low and behold it works. Finally got one of the last three remaining "Statement Fetchers" to work.

This works beautifully.

2 Likes

Would anyone know if there Is a way to adapt this function to instead click on the FIRST xpath found, to be able to click on the nth occurrence of the xpath

I ask because a web page I am trying to automate uses the same xpath for all the buttons, so it would be ideal to be able to say "click on the 5th occurence of the xpath"

I prefer using querySelector to XPath.

Here is an example of clicking on the nth link:

From: @Web Add Number to Search Link and Click by Number @Example

Hi Michael!

Thank you for the code, it works in most cases.
I have an issue with some element of the website.
For example I have this table and want to click on a element of this table (had to delete closing html tags as it wouldn't display correctly):

`<table id="treeview-1450-record-12558" role="presentation" data-boundview="treeview-1450" data-recordid="12558" data-recordindex="11" class="x-grid-item" cellpadding="0" cellspacing="0" style=";width:0"
<tbody
<tr class="x-grid-tree-node-expanded  x-grid-row" role="row" data-qtip="" data-qtitle=""
<td class="x-grid-cell x-grid-td x-grid-cell-treecolumn-1449 x-grid-cell-treecolumn x-grid-cell-first x-grid-cell-last x-unselectable" role="gridcell" style="width:223px;" tabindex="-1" data-columnid="treecolumn-1449"
<div unselectable="on" class="x-grid-cell-inner x-grid-cell-inner-treecolumn" style="text-align:left;"
<div class=" x-tree-elbow-img x-tree-elbow-empty" role="presentation"
</div <div class=" x-tree-elbow-img x-tree-elbow-end-plus x-tree-expander" role="presentation" </div <div role="presentation" class=" x-tree-icon x-tree-icon-parent-expanded " </div <span class="x-tree-node-text "123</span </div </td </tr </tbody </table `

I use this xPath:
//table[@id='treeview-1450-record-12558']/tbody/tr[1]/td[1]/div[1]/div[3]

Also, the field I am trying to click on is dynamically changing color when you hover over it.

Any suggestions what should I change for it to work?

I'm just coming up to speed on web-automation / scraping. What are plusses / minuses of using XPath vs CSS selector vs DOM (getElementBy...). - Particularly for the environment of MacOS / Safari / AppleScript / JavaScript / KM?

I started with the last of those three, so its my comfort zone. For my use they seem to have a lot of overlap - I open a page in developer tools & can click a feature to find its 'magic string' - whether xpath, CSS selector, etc. And then use that magic string to reference it via script.

I haven't started using jquery yet, but i'll likely get there soon.

I have addressed this numerous times.
I find that querySelector() - Web APIs | MDN is much easier to use than XPath.
While you can get both the absolute path for Xpath and querySelector CSS using the Chrome tools, that path is rarely what you really want.
Often you will want a CSS that is either not dependent on its prior elements, or reoccurs throughout the web page.

Using querySelector takes only one statement to get the target HTML element, whereas Xpath requires multiple statements, often in a loop.

If you do a Forum search on "querySelector" you will find many of my posts on this subject.
There are also many posts on the Internet at Stackoverflow.com and elsewhere that provide good help on querySelector.

2 Likes

Looking for the same automation. My case is a little bit complicated:

  1. first find a "div" element contains text "ABC" and click it.
  2. then find a "span" element contains text "DEF" and click it.
  3. finally find a "a" element that contains text "GHI" and click it.
    Does the querySelector way works? Is the parameter for querySelector coming from chrome devtool "copy selector"?

Thanks!