How to calculate the XPath position of an element using Javascript?

Viewed 40073

Let's say I have a large HTML file with different kinds of tags, similar to the StackOverflow one you're looking at right now.

Now let's say you click an element on the page, what would the Javascript function look like that calculates the most basic XPath that refers to that specific element?

I know there are an infinite ways of refering to that element in XPath, but I'm looking for something that just looks at the DOM tree, with no regard for IDs, classes, etc.

Example:

<html>
<head><title>Fruit</title></head>
<body>
<ol>
  <li>Bananas</li>
  <li>Apples</li>
  <li>Strawberries</li>
</ol>
</body>
</html>

Let's say you click on Apples. The Javascript function would return the following:

/html/body/ol/li[2]

It would basically just work its way upward the DOM tree all the way to the HTML element.

Just to clarify, the 'on-click' event-handler isn't the problem. I can make that work. I'm just not sure how to calculate the element's position within the DOM tree and represent it as an XPath.

PS Any answer with or without the use of the JQuery library is appreciated.

PPS I completely new to XPath, so I might even have made a mistake in the above example, but you'll get the idea.

Edit at August 11, 2010: Looks like somebody else asked a similar question: generate/get the Xpath for a selected textnode

11 Answers

Use https://github.com/KajeNick/jquery-get-xpath

<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="../src/jquery-get-xpath.js"></script> 

<script>
    jQuery(document).ready(function ($) {

        $('body').on('click', 'ol li', function () {
           let xPath = $(this).jGetXpath();

           console.log(xPath);
        });

    });
</script>

Console will show: /html/body/ol/li[2]

I have came across this problem and found it hard to solve fully. as in my case it was giving half xpath. so i modified it a little to give full path. here is my answer.

window.onclick = (e) => {
    let pathArr = e.path;
    let element = pathArr[0];
    var xpath = '';
if(pathArr.length<=2 && pathArr[0].nodeType!=1){
    for (let i = 0; i < pathArr.length - 1 && pathArr[i].nodeType == 1; i++) {
        element = pathArr[i];
        var id = $(element.parentNode).children(element.tagName).index(element) + 1;
        id > 1 ? (id = '[' + id + ']') : (id = '');
        xpath = '/' + element.tagName.toLowerCase() + id + xpath;
    }
}
else{
  xpath="/html/document"
}
    return xpath;
Related