我正在尝试从Javascript中的UL元素构建JSON对象。
我有这个列表结构:
<ul id="trainingmenu">
<li class="tmnode"><span id="M5lx9n" class="tmname">menu 1</span>
<ul>
<li class="tmnode"><span id="M66p48" class="tmname">menu 2</span>
<ul>
<li class="tmnode"><span class="tmname" id="Mschr">menu 3</span>
</li>
</ul>
</li>
<li class="tmnode"><span id="Mu03e0" class="tmname">menu 4</span></li>
</ul>
</li>
</ul>
这是JS:
var treeObject = {};
function treeHTML(element, object) {
if (element.tagName=="UL") { element=element.firstChild; }
object["id"] = element.firstChild.id;
object["name"] = element.firstChild.innerHTML;
var nodeList = element.getElementsByTagName('LI');
if (nodeList[0]) {
object["nodes"] = [];
for (var i = 0; i < nodeList.length; i++) {
object["nodes"].push({});
treeHTML(nodeList[i], object["nodes"][object["nodes"].length - 1]);
}
}
}
treeHTML(document.getElementById("trainingmenu"), treeObject);
alert(JSON.stringify(treeObject));
..这是我得到的输出:
{"id":"M5lx9n","name":"menu 1","nodes":[{"id":"M66p48","name":"menu 2","nodes":[{"id":"Mschr","name":"menu 3"}]},{"id":"Mschr","name":"menu 3"},{"id":"Mu03e0","name":"menu 4"}]}
这是部分工作,这是我想要的格式 - 从每个LI元素的childNode中挑选id和name字段。但它重复节点 - 菜单3出现两次
这是fiddle
我可能搞砸了递归,但是盯着它看了2天还没有弄明白。有人可以帮忙吗?
答案 0 :(得分:1)
它正在重复节点,因为element.getElementsByTagName
正在查找所有后代,而不仅仅是孩子。您可能想要测试nodeList[i].parentNode == element
。
或者直接遍历所有元素的子节点(element.childNodes
或element.children
),并查找tagName == 'li'
的节点。在格式良好的HTML中,您应该只在li
元素的子列表中找到(空白)文本节点和ul
元素。
答案 1 :(得分:1)
正如Alnitak所提到的,您应该使用.children
或.childNodes
属性而不是.getElementsByTagName()
方法。以下代码段使用数组原型的.filter()
方法过滤ul
个子项,使用.forEach()
进行迭代。
function treeHTML(element) {
var o = {};
o.id = element.firstElementChild.id;
o.name = element.firstElementChild.innerHTML;
o.nodes = [];
[].slice.call(element.children).filter(function(e) {
return e.tagName.toLowerCase() === 'ul';
}).forEach(function(ul) {
[].slice.call(ul.children).forEach(function(li) {
o.nodes.push(treeHTML(li));
});
});
return o;
}
var treeObj = treeHTML(document.getElementById("trainingmenu")
.firstElementChild);
这是一个替代解决方案,它也适用于旧版本的IE:
function children(node, selector) {
var res = [], nodes = node.childNodes, l = nodes.length;
for (var i = 0; i < l; i++) {
if (nodes[i].nodeType === 1) {
if (selector && nodes[i].tagName.toLowerCase() === selector) {
res.push(nodes[i]);
} else if (!selector) {
res.push(nodes[i]);
}
}
}
return res;
}
function treeHTML(element) {
var o = {};
var span = children(element, 'span');
o.id = span[0].id;
o.name = span[0].innerHTML;
o.nodes = [];
var ul = children(element, 'ul'), n = ul.length;
for (var i = 0; i < n; i++) {
var li = children(ul[i]), l = li.length;
for (var j = 0; j < l; j++) {
o.nodes.push(treeHTML(li[j]));
}
}
return o;
}
var root = document.getElementById("trainingmenu");
var treeObj = treeHTML(children(root)[0]);