0

我编写了一个递归函数,它遍历以下形式的嵌套 DOM 节点:

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

递归函数如下:

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

所以如果我这样调用该函数:

var links = document.querySelectorAll('a');
console.log(JSON.stringify(getNestedNodes(links)));

它应该返回以下形式的 JSON 数组:

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

但是,它只返回以下形式之一:

 [{
   "tag":"DIV",
   "id":"nested-image",
   "children":[{
                "tag":"IMG",
                 "src":"https://www.gravatar.com/avatar/d1a336ae4b6876a4c5c044ec17876ce0",
                "children":[]
              }]
 }] 

而且我无法以正确的方式获得我想要的表格,而不会得到空结果或重复结果。

另外,我想优化我的递归函数,我确信我可以重构为更具可读性的东西。

这是一个小提琴供您查看:

http://jsfiddle.net/DfHqv/

任何帮助将不胜感激!

4

3 回答 3

3

问题是您已经使您的函数预期接收一个集合,但您正在循环其中的两个节点集合。

因此,您似乎不是从外循环推入节点,而只是推入子节点。这可以解释为什么你没有达到最高水平。

只需将其保留在一个节点循环中(当然,然后是一个 for 属性),然后不要在新循环中循环子节点,只需将其传递给递归调用即可。

function getNestedNodes(nodeList) {
    var ary = [];

    // Loop the collection of nodes
    for(var i = 0; i < nodeList.length; ++i) {
        var node = nodeList[i];

        // Create the new object with the "tag" populated
        var jsonNode = {"tag":node.nodeName};

        // Add the attributes to the object
        for(var k =0, attrs = node.attributes, l = attrs.length; k < l; ++k) {
            jsonNode[attrs.item(k).nodeName] = attrs.item(k).nodeValue;
        }

        // Make a recursive call if any children are present, and add the result
        if (node.children && node.children.length)
            jsonNode['children'] = getNestedNodes(node.children);

        ary.push(jsonNode);
    }
    return ary;
}

演示:http: //jsfiddle.net/argA3/1/

[
    {
        "tag": "A",
        "title": "test",
        "href": "#",
        "children": [
            {
                "tag": "DIV",
                "id": "nested-image",
                "children": [
                    {
                        "tag": "IMG",
                        "src": "image.jpg"
                    }
                ]
            }
        ]
    }
]
于 2013-06-28T15:06:44.100 回答
1

这似乎有效:

function getNestedNodes(nodeList) {
    var ary = [];
    for (var i = 0; i < nodeList.length; i += 1) {
        var attributes = {};
        for (var key in nodeList[i].attributes) {
            attributes[nodeList[i].attributes.item(key).nodeName] = nodeList[i].attributes.item(key).nodeValue;
        }
        ary.push({
            tag: nodeList[i].nodeName,
            attributes: attributes,
            children: getNestedNodes(nodeList[i].children)
        });
    }
    return ary;
}

var links = document.querySelectorAll('a');
console.log(JSON.stringify(getNestedNodes(links)));

输出:

[{"tag":"A","attributes":{"href":"#","title":"test"},"children":[{"tag":"DIV","attributes":{"id":"nested-image"},"children":[{"tag":"IMG","attributes":{"src":"https://www.gravatar.com/avatar/d1a336ae4b6876a4c5c044ec17876ce0?s=32&d=identicon&r=PG"},"children":[]}]}]}] 
于 2013-06-28T15:07:36.867 回答
1

由于我们都在提供各种(重构)出价:

// getNestedNodes2(nodeList)
// @nodeList: a collection of nodes to serialize
function getNestedNodes2(nodeList){
    // iterate over the node collection
    for (var i = 0, result = []; i < nodeList.length; i++){
        // begin building a definition of the current node
        var thisNode = {
            tag: nodeList[i].tagName
        };
        // iterate over any attributes on the current node and add them
        // to the current definition.
        for (var j = 0, attributes = nodeList[i].attributes; j < attributes.length; j++){
            thisNode[attributes.item(j).nodeName] = attributes.item(j).nodeValue;
        }
        // check for child elements and, if present, also add them to
        // the definition
        if (nodeList[i].childElementCount > 0){
            thisNode.children = getNestedNodes2(nodeList[i].children);
        }
        // add the definition to the results set
        result.push(thisNode);
    }
    // return the results
    return result;
}

最终结果

[
  {
    "tag": "A",
    "title": "test",
    "href": "#",
    "children": [
      {
        "tag": "DIV",
        "id": "nested-image",
        "children": [
          {
            "tag": "IMG",
            "src": "https://www.gravatar.com/avatar/d1a336ae4b6876a4c5c044ec17876ce0?s=32&d=identicon&r=PG"
          }
        ]
      }
    ]
  }
]

请记住,您正在接受一个集合,这意味着当您直接迭代它们并仅构建子项的定义时,第一次调用中的节点将被忽略。相反,首先处理接收到的集合中的节点,然后让递归处理子节点。

于 2013-06-28T15:18:05.620 回答