1

For example I have HTML like this

<body> 
   <div> 
     something. 
   </div> 
   <div> 
     something else 
   </div> 
   <div> 
     <a> something. </a>
     <a> ELEMENT </a> 
   </div> 
</body>

Is there a way to get path from the root to the ELEMENT by using JS, something like this:

body[0]/div[2]/a[1]

So, for the ELEMENT there is need to look on the parent node, check if there exist siblings with the same tag and then correctly assign value and do it recursively to root.

So, for the ELEMENT it is the second (a[1]) child of parent root div which is third (div[2]) child of body.

Is there any way this can be done with JS?

Petr Krčmárik
  • 221
  • 1
  • 2
  • 13
  • Might be a duplicate of [is-there-a-way-to-get-element-by-xpath-in-javascript](http://stackoverflow.com/questions/10596417/is-there-a-way-to-get-element-by-xpath-in-javascript) – user2314737 May 27 '15 at 09:16
  • It is not a duplicate of the above link. This PR searches in the other direction than the implied duplicate. – U Rogel Aug 13 '20 at 00:12

3 Answers3

0

This might be what you were looking for. Else I am sorry I missunderstood your question.

<html>
    <head>
        <script>
            //Recursive function to get element path until html from passed element e;
            function getPath(e, d){
                d = (d || []);

                //if (!e || e.tagName === 'BODY'){ //Body is obivous in most cases tho.
                if (!e || !e.parentNode){
                    return d.join('/');
                }
                else{
                    //j is needed since <head> is previous sibling to <body> :s
                    for (var i = 0, n = e, j = 0; n = n.previousElementSibling; i++) if (n.tagName === e.tagName) j++;

                    //Here we add the element to the current path \o/
                    d.push(e.tagName.toLowerCase() + '[' + j.toString() + ']');
                    return getPath(e.parentNode, d);
                };
            };
        </script>
    </head>

    <body onclick = 'alert(getPath(this));'>
        <div>something.</div> 
        <div>something else</div> 
        <div> 
            <a onclick = 'alert(getPath(this));'>something.</a>
            <a onclick = 'alert(getPath(this));'>ELEMENT</a> 
        </div> 
    </body>
</html>
Lain
  • 3,657
  • 1
  • 20
  • 27
0

One approach is the following:

function findIndexOfLike(node) {
  // creating an Array of the filtered children of the node's
  // parent element (using Array.prototype.filter() with
  // Function.prototype.call() to apply the Array method
  // to the Array-like collection):
  var children = Array.prototype.filter.call(node.parentNode.children, function(child) {

    // keeping only those elements that are of the same
    // tagName:
    return node.tagName === child.tagName;
  });

  // Using Array.prototype.indexOf() to find the index of
  // the node from the array of children; and returning that:
  return children.indexOf(node);

}

function createIndexedPathTo(node) {

  // an empty Array to contain the path:
  var path = [],

    // initialising the 'current' variable, which we'll
    // use to move upwards through the document:
    current = node;

  // while the node contained in the 'current' variable is
  // not the <body> element:
  while (current.tagName.toLowerCase() !== 'body') {

    // we push the lower-cased tagName of the 'current' node,
    // along with its index, to the array:
    path.push(current.tagName.toLowerCase() + '[' + findIndexOfLike(current) + ']');

    // move the 'current' variable to the parentNode of
    // the current element (to move 'up'):
    current = current.parentNode;
  }

  // there can be only one <body> element, but since
  // you seem to want it listed we add it here:
  path.push('body[0]');

  // now we reverse the array, and join it together,
  // with the '/' character, to form a string, returning
  // that formed string:
  return path.reverse().join('/');
}

// calling the function, passing it a DOM Node from which to start:
var route = createIndexedPathTo(document.querySelector('a:nth-child(2)'));

// setting the 'data-routeto' attribute of the <body>
// in order to display that route/path in the document
// using CSS generated content:
document.body.dataset.routeto = route;

function findIndexOfLike(node) {
  var children = Array.prototype.filter.call(node.parentNode.children, function(child) {
    return node.tagName === child.tagName;
  });
  return children.indexOf(node);

}

function createIndexedPathTo(node) {
  var path = [],
    current = node;
  while (current.tagName.toLowerCase() !== 'body') {
    path.push(current.tagName.toLowerCase() + '[' + findIndexOfLike(current) + ']');
    current = current.parentNode;
  }
  path.push('body[0]');
  return path.reverse().join('/');
}

var route = createIndexedPathTo(document.querySelector('a:nth-child(2)'));

document.body.dataset.routeto = route;
body::before {
  display: block;
  content: 'Route to "Example" element: ' attr(data-routeto);
  color: #999;
}
<div>something.</div>
<div>something else</div>
<div> <a> something. </a>
  <a id="demo"> ELEMENT </a> 
</div>

External JS Fiddle demo, for experimentation.

References:

David Thomas
  • 249,100
  • 51
  • 377
  • 410
-1
javascript: (function() {
    if ( typeof document.getElementsByTagName === 'function') {
        var elemTag = document.getElementsByTagName('input');
        for (var i = 0; i < elemTag.length; i++) {
            elemTag[i].addEventListener('mouseup', getPath);
        }
        var elemTag2 = document.getElementsByTagName('a');
        for (var j = 0; j < elemTag2.length; j++) {
            elemTag2[j].addEventListener('mouseup', getPath);
        }
        var elemTag3 = document.getElementsByTagName('select');
        for (var p = 0; p < elemTag3.length; p++) {
            elemTag3[p].addEventListener('mouseup', getPath);
        }
        var elemTag4 = document.getElementsByTagName('button');
        for (var m = 0; m < elemTag4.length; m++) {
            elemTag4[m].addEventListener('mouseup', getPath);
        }
        var elemTag5 = document.getElementsByTagName('img');
        for (var l = 0; l < elemTag5.length; l++) {
            elemTag5[l].addEventListener('mouseup', getPath);
        }
    }
    function getPath() {
        var domPathArr = [],
            elm,
            entry;
        elm = this;
        if ( typeof getIndex === "function" && elm) {
            entry = elm.tagName.toLowerCase() + "[" + getIndex(elm) + "]";
            if (entry) {
                domPathArr.push(entry);
                for ( elm = this.parentNode; elm; elm = elm.parentNode) {
                    entry = elm.tagName.toLowerCase();
                    if (entry === "html") {
                        break;
                    }
                    if (elm) {
                        entry += "[" + getIndex(elm) + "]" + "/";
                    }
                    domPathArr.push(entry);
                }
            }
        }
        domPathArr.reverse();
        console.log(domPathArr.join(' '));
    }

    function getIndex(elm) {
        var count = 0;
        if (elm) {
            for (var siblingElm = elm.previousSibling; siblingElm; siblingElm = siblingElm.previousSibling) {
                if (siblingElm.nodeName == elm.nodeName)
                    count++;
            }
        }
        return count;
    }

})(); 
Dusty
  • 354
  • 4
  • 15