3
\$\begingroup\$

I wrote a recursive function that traverses nested DOM nodes of the following form:

<a href="#" title="test">
    <div id="nested-image">
          <img src="image.jpg" />
    </div>
</a>

The recursive function is the following:

function getNestedNodes(node) {
var ary = [];
for(var i = 0; i < node.length; ++i) {
    var myJSONChildren = {};
    if(node[i].childElementCount) {
        var myNode = node[i].children;
        for(var j = 0; j < myNode.length; ++j) {
            for(var k =0, attrs = myNode[j].attributes, l = attrs.length; k < l; ++k) {
                myJSONChildren['tag'] = myNode[j].nodeName;
                myJSONChildren[attrs.item(k).nodeName] = attrs.item(k).nodeValue;
            };
        }
        myJSONChildren['children'] = getNestedNodes(myNode); //Recursive Call
        ary.push(myJSONChildren);
    };
}
return ary;
}

so if I call that function this way:

var links = document.querySelectorAll('a');
getNestedNodes(node);

it returns a JSON array of the following form:

[{
  tag:'a',
  href:"#,
  title:"test",
  children:[{
             tag:"div",
             id:"nested-image",
             children:[{
                        tag:"img",
                        src:"image.jpg"
                       }]
             }]
  }]
}]

However, I think that my function is way too complex, and I know that there must a better way to get the same results.

Any help will be greatly appreciated!

\$\endgroup\$
1

1 Answer 1

4
\$\begingroup\$

Note that when you do document.querySelectorAll you are getting not a single node but a list of nodes. This seems to be causing confusion because your function refers to node.length - but a single node does not have any length property. Your original function also does not seem to behave exactly as you want it to in that it excludes the parent node (a in your example).

If you ensure that you are passing the function a single node, then it can indeed be simplified a lot:

function getTree(node) {
    var r = {tag: node.nodeName}, a, i;
    if (node.childElementCount) {
        r.children = [];
        for (i = 0; a = node.children[i]; i++) {
            r.children.push(getTree(a));
        }
    }
    for (i = 0; a = node.attributes[i]; i++) {
        r[a.nodeName] = a.nodeValue;
    }
    return r;        
}
var links = document.querySelectorAll('a');
console.log(getTree(links[0])); // only pass the first node to the function

(JSfiddle here)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.