26

I am traversing a HTML document using javascript DOM. I want make a list (an array actually) of all nodes/elements and their values. I found a script for traversing DOM, but how do I store each node value in an array. I can't seem to find the unique identifier for a node. Anyone has any pointers? I was thinking of xpath or something.

Is it a good idea to consider xpath for node as the unique identifier. If so how do I get xpath of a element while traversing the DOM?

Seanny123
  • 8,776
  • 13
  • 68
  • 124
Annibigi
  • 5,895
  • 5
  • 23
  • 21

2 Answers2

29

As programmer born and brought up in the world of C and C++, my first answer to this kind of question would have been "store their addresses in the array!". But after a couple years of messing around with the web way of things, I can give the right answer:

In javascript, you can directly store the references to the objects in the array. And no, xpath is not a good idea for this; using references is simpler and better. So a direct answer to your question is: there is no unique identifier for a DOM element/node except itself.

In javascript, all objects are passed around by reference. So here's a sample code for how to do it:

var theArray = [];
var theNodeToTraverse = document.getElementById('domelementtosearch');

traverseAndStore(theNodeToTraverse);

function traverseAndStore( node )
{
    if( node==null) return;
    theArray[ theArray.length ] = node;
    for( i=0; i<node.childNodes.length; i++ )
        traverseAndStore( node.childNodes[i] );
}
Seanny123
  • 8,776
  • 13
  • 68
  • 124
jrharshath
  • 25,975
  • 33
  • 97
  • 127
  • this code simply traverses all the children of `theNodeToTraverse`, and stores references to the child DOM elements in `theArray`. – jrharshath Mar 10 '11 at 05:25
  • 3
    Can such references be used as unique ids? For example, could I store it somewhere and re-use it in another javascript script to access the same node? If not (as I suspect), then how would you "remember" a node between scripts? – Shawn Apr 27 '12 at 07:56
  • "remembering nodes between scripts" - if they are just different scripts (read different js files) loaded on the same page, and you want to pass the reference around (using a method call, or a shared space), you can absolutely do it. What you can't do is pass store the reference somehow in a database, and then pass it back later to that page expecting it to be usable. – jrharshath Apr 30 '12 at 04:49
  • 1
    @jrharshath that is precisely what *I* would like to do, any ideas? – lsl Dec 06 '12 at 22:37
  • I have now :) Sadly, I don't do it for a living. – jrharshath May 08 '13 at 13:09
  • It's really disappointing JS only allows comparing references (which are basically just addresses), but not getting their actual values. In case you need a map of `element:value`, your only option is to store the pairs of `element,value` in an array, and perform linear search each time you need to retrieve something. A plain JS object with addresses as keys would've achieved O(1) retrieval. – Avidan Borisov Jul 29 '14 at 12:09
  • @AvidanBorisov ES2015 *computed keys* / *object-initializer*... Those do exactly what you're talking about: `{ [element]: value }` http://www.ecma-international.org/ecma-262/6.0/#sec-object-initializer – yckart Jun 11 '18 at 13:15
2

You can get something similar to xpath with something like this. It traverses the dom upwards from the input element through the parentNode property.

https://gist.github.com/sebjwallace/3c0a6f7493ce23134516

It will output a string like this.

"#document/HTML/BODY/DIV"

var getElementPath = function(el){
  var path = el.nodeName;
  var parent = el.parentNode;
  while(parent){
    path = parent.nodeName + '/' + path;
    parent = parent.parentNode;
  }
  return path;
}

EDIT: The question seems to point to a simple flatmap solution. I think my original answer was aimed at generating an address for each node in the DOM. This solution almost as basic as flatmap. Well, the DOM is a tree with N children per node. Given a snapshot of the DOM you can generate an address of each element given the child index. As an example of stackoverflow's DOM, grabbing the one of the nodes 5 levels deep - the address is 01001. Each address will be unique for every element in the DOM. This won't work if you need a static address for a dynamic web app however.

enter image description here

sebjwallace
  • 753
  • 1
  • 8
  • 17
  • 10
    For the purposes of a unique id, this would fail if there were two DIV's that were children of the BODY element, as both would have the same output string. This would invalidate the uniqueness of this as an id. – Joe B. Mar 14 '17 at 18:29
  • Can you update the answer with something that makes it unique? – mesqueeb Nov 28 '21 at 05:19
  • Sure thing @mesqueeb – sebjwallace Apr 18 '22 at 21:14
  • @sebjwallace can you update your answer to include the code snippet how you calculate those numbers? I'm curious to see. I'll upvote. – mesqueeb Apr 18 '22 at 23:13