Here's a simple function to get leafNodes where you look at all nodes, including text nodes (this means it won't ever return an element that contains text nodes):
function getLeafNodes(master) {
var nodes = Array.prototype.slice.call(master.getElementsByTagName("*"), 0);
var leafNodes = nodes.filter(function(elem) {
return !elem.hasChildNodes();
});
return leafNodes;
}
Working demo: http://jsfiddle.net/jfriend00/e9D5n/
FYI, the .filter()
method requires IE9. If you want to use this method with earlier versions of IE, you can install a polyfill for .filter()
or change to a manual iteration of the array.
And, here's a version if you don't want to consider text nodes, so you're looking for the leaf elements, even if they have text nodes in them:
function getLeafNodes(master) {
var nodes = Array.prototype.slice.call(master.getElementsByTagName("*"), 0);
var leafNodes = nodes.filter(function(elem) {
if (elem.hasChildNodes()) {
// see if any of the child nodes are elements
for (var i = 0; i < elem.childNodes.length; i++) {
if (elem.childNodes[i].nodeType == 1) {
// there is a child element, so return false to not include
// this parent element
return false;
}
}
}
return true;
});
return leafNodes;
}
Working demo: http://jsfiddle.net/jfriend00/xu7rv/
And, here's a recursive solution that ignores text nodes:
function getLeafNodes(master) {
var results = [];
var children = master.childNodes;
for (var i = 0; i < children.length; i++) {
if (children[i].nodeType == 1) {
var childLeafs = getLeafNodes(children[i]);
if (childLeafs.length) {
// if we had child leafs, then concat them onto our current results
results = results.concat(childLeafs);
} else {
// if we didn't have child leafs, then this must be a leaf
results.push(children[i]);
}
}
}
// if we didn't find any leaves at this level, then this must be a leaf
if (!results.length) {
results.push(master);
}
return results;
}
Working demo: http://jsfiddle.net/jfriend00/jNn8H/