Posted By

wizard04 on 09/05/08


Tagged

javascript DOM tree traversal


Versions (?)

Who likes this?

2 people have marked this snippet as a favorite

jamesming
jschilling


DOM Traversal


 / Published in: JavaScript
 

  1. //nodeType "constants"
  2. if(!document.ELEMENT_NODE)
  3. {
  4. document.ELEMENT_NODE = 1;
  5. document.ATTRIBUTE_NODE = 2;
  6. document.TEXT_NODE = 3;
  7. document.CDATA_NODE = 4;
  8. document.ENTITY_REFERENCE_NODE = 5;
  9. document.ENTITY_NODE = 6;
  10. document.PROCESSING_INSTRUCTION_NODE = 7;
  11. document.COMMENT_NODE = 8;
  12. document.DOCUMENT_NODE = 9;
  13. document.DOCUMENT_TYPE_NODE = 10;
  14. document.DOCUMENT_FRAGMENT_NODE = 11;
  15. document.NOTATION_NODE = 12;
  16. }
  17.  
  18. //get an element by its ID
  19. //returns null if not found
  20. function $id(id)
  21. {
  22. var elem = document.getElementById(id);
  23. if(elem && elem.id == id) return elem;
  24. //in IE, getElementById() returns the first element with *either* a matching id or a matching name
  25. else if(elem) //it returned an element without a matching id
  26. {
  27. var nodes = document.getElementsByTagName("*");
  28. for(var i=0; i<nodes.length; i++)
  29. {
  30. if(nodes[i].id == id) return nodes[i]; //first element with a matching id
  31. }
  32. }
  33. return null;
  34. }
  35.  
  36. //get elements by tag name
  37. function $tag(tag)
  38. {
  39. var nodes = document.getElementsByTagName(tag); //if tag=="*", IE returns comment nodes as well (including DOCTYPE)
  40. //`nodes` is now a NodeList or HTMLCollection object; this function converts it to an array
  41. var elems = [];
  42. for(var i=0; i<nodes.length; i++)
  43. {
  44. if(nodes[i].nodeType == document.ELEMENT_NODE) elems.push(nodes[i]); //add the element to the array
  45. }
  46. return elems;
  47. }
  48.  
  49.  
  50. //*******************************************************************//
  51. //***** to deal with empty text/CDATA nodes (i.e., ignore them) *****//
  52. //*******************************************************************//
  53.  
  54. function getPreviousSibling(obj)
  55. {
  56. var prevNode = obj.previousSibling;
  57. while(prevNode && (prevNode.nodeType == document.TEXT_NODE || prevNode.nodeType == document.CDATA_NODE) && prevNode.nodeValue.match(/^\s*$/)) //it's an empty text node
  58. {
  59. prevNode = prevNode.previousSibling;
  60. }
  61. return prevNode;
  62. }
  63.  
  64. function getNextSibling(obj)
  65. {
  66. var nextNode = obj.nextSibling;
  67. while(nextNode && (nextNode.nodeType == document.TEXT_NODE || nextNode.nodeType == document.CDATA_NODE) && nextNode.nodeValue.match(/^\s*$/)) //it's an empty text node
  68. {
  69. nextNode = nextNode.nextSibling;
  70. }
  71. return nextNode;
  72. }
  73.  
  74. function getChildNodes(obj)
  75. {
  76. var children = obj.childNodes;
  77. var nodes = [];
  78. for(var i=0; i<children.length; i++)
  79. {
  80. if((children[i].nodeType == document.TEXT_NODE || children[i].nodeType == document.CDATA_NODE) && children[i].nodeValue.match(/^\s*$/)) continue; //it's an empty text node
  81. nodes.push(children[i]);
  82. }
  83. return nodes;
  84. }
  85.  
  86. //**********************************//
  87. //***** get element nodes only *****//
  88. //**********************************//
  89.  
  90. function getPreviousElement(obj)
  91. {
  92. var prevNode = obj.previousSibling;
  93. while(prevNode && prevNode.nodeType != document.ELEMENT_NODE) //it's not an element node
  94. {
  95. prevNode = prevNode.previousSibling;
  96. }
  97. return prevNode;
  98. }
  99.  
  100. function getNextElement(obj)
  101. {
  102. var nextNode = obj.nextSibling;
  103. while(nextNode && nextNode.nodeType != document.ELEMENT_NODE) //it's not an element node
  104. {
  105. nextNode = nextNode.nextSibling;
  106. }
  107. return nextNode;
  108. }
  109.  
  110. function getChildElements(obj)
  111. {
  112. var children = obj.childNodes;
  113. var elems = [];
  114. if(children)
  115. {
  116. for(var i=0; i<children.length; i++)
  117. {
  118. if(children[i].nodeType == document.ELEMENT_NODE) //it's an element node
  119. {
  120. elems.push(children[i]);
  121. }
  122. }
  123. }
  124. return elems;
  125. }
  126.  
  127. //get descendant elements of obj
  128. function getDescendantElements(obj, childrenOnly)
  129. {
  130. var elems = getChildElements(obj);
  131. var results = [];
  132. for(var i=0; i<elems.length; i++)
  133. {
  134. results.push(elems[i]);
  135. if(!childrenOnly)
  136. {
  137. results = results.concat(getDescendantElements(elems[i]));
  138. }
  139. }
  140. return results;
  141. }
  142.  
  143. //get ancestral elements of obj (nearest first)
  144. function getAncestralElements(obj)
  145. {
  146. var results = [];
  147. while(obj.parentNode)
  148. {
  149. obj = obj.parentNode;
  150. results.push(obj);
  151. }
  152. return results;
  153. }
  154.  
  155. //get elements of type tagName that are descendants of obj
  156. function getDescendantsByTagName(obj, tagName, childrenOnly)
  157. {
  158. var results = [];
  159. if(!tagName) return results;
  160. tagName = tagName.toLowerCase();
  161. var elems = getChildElements(obj);
  162. for(var i=0; i<elems.length; i++)
  163. {
  164. if(elems[i].nodeName.toLowerCase() == tagName) results.push(elems[i]);
  165. if(!childrenOnly)
  166. {
  167. results = results.concat(getDescendantsByTagName(elems[i], tagName));
  168. }
  169. }
  170. return results;
  171. }
  172.  
  173. //get elements of type tagName that are ancestors of obj (nearest first)
  174. function getAncestorsByTagName(obj, tagName, nearestOnly)
  175. {
  176. var results = [];
  177. if(!tagName) return results;
  178. tagName = tagName.toLowerCase();
  179. while(obj.parentNode)
  180. {
  181. obj = obj.parentNode;
  182. if(obj.nodeName.toLowerCase() == tagName)
  183. {
  184. results.push(obj);
  185. if(nearestOnly) break;
  186. }
  187. }
  188. return results;
  189. }
  190.  
  191. //get elements with class(es) className that are descendants of obj
  192. function getDescendantsByClassName(obj, className, childrenOnly)
  193. {
  194. var results = [];
  195. if(!className) return results;
  196. var elems = getChildElements(obj);
  197. var classes = className.match(/(^|\s)\S+(\s|$)/ig);
  198. var rexp;
  199. var j;
  200. for(var i=0; i<elems.length; i++)
  201. {
  202. for(j=0; j<classes.length; j++)
  203. {
  204. classes[j] = classes[j].replace(/\s?(\S+)\s?/, "$1");
  205. rexp = new RegExp("(^|\\s)"+classes[j]+"(\\s|$)");
  206. if(!rexp.test(elems[i].className)) break; //one of the classes was not found
  207. }
  208. if(j == classes.length) results.push(elems[i]); //if elems[i].className includes all the classes, add elems[i]
  209. if(!childrenOnly)
  210. {
  211. results = results.concat(getDescendantsByClassName(elems[i], className));
  212. }
  213. }
  214. return results;
  215. }
  216.  
  217. //get elements with class(es) className that are ancestors of obj (nearest first)
  218. function getAncestorsByClassName(obj, className, nearestOnly)
  219. {
  220. var results = [];
  221. if(!className) return results;
  222. var classes = className.match(/(^|\s)\S+(\s|$)/ig);
  223. var rexp;
  224. var j;
  225. while(obj.parentNode)
  226. {
  227. obj = obj.parentNode;
  228. for(j=0; j<classes.length; j++)
  229. {
  230. classes[j] = classes[j].replace(/\s?(\S+)\s?/, "$1");
  231. rexp = new RegExp("(^|\\s)"+classes[j]+"(\\s|$)");
  232. if(!rexp.test(obj.className)) break; //one of the classes was not found
  233. }
  234. if(j == classes.length) //if obj.className includes all the classes
  235. {
  236. results.push(obj);
  237. if(nearestOnly) break;
  238. }
  239. }
  240. return results;
  241. }
  242.  
  243. //get elements with a path such as "div.class1 span.class2a.class2b * .class3"
  244. function getDescendantsByPath(obj, path)
  245. {
  246. var results = [];
  247.  
  248. if(!path) return results;
  249. var node = path.split(" ")[0];
  250. path = path.slice(node.length+1);
  251. var attrs = node.split(".");
  252. if(!attrs) return results;
  253.  
  254. var elems = getChildElements(obj);
  255. var rexp;
  256. var j;
  257. for(var i=0; i<elems.length; i++)
  258. {
  259. if(attrs[0] && attrs[0] != "*" && elems[i].nodeName.toLowerCase() != attrs[0]) continue; //if a tag name was specified but it doesn't match
  260. for(j=1; j<attrs.length; j++)
  261. {
  262. if(!attrs[j]) continue;
  263. rexp = new RegExp("(^|\\s)"+attrs[j]+"(\\s|$)");
  264. if(!rexp.test(elems[i].className)) break; //one of the classes was not found
  265. }
  266. if(j == attrs.length) //if elems[i].className includes all the classes
  267. {
  268. if(path) //if there is more to the path
  269. results = results.concat(getDescendantsByPath(elems[i], path));
  270. else
  271. results.push(elems[i]);
  272. }
  273. }
  274. return results;
  275. }

Report this snippet  

Comments

RSS Icon Subscribe to comments
Posted By: wizard04 on May 6, 2010

Replaced $() with $id(), and added $tag()

You need to login to post a comment.