2014-05-04 144 views
0

我有以下有效的JSON。它描述了一个树形结构:嵌套JSON查找项目

{ 
"items": [ 
    { 
     "id": "d1" 
    }, 
    { 
     "id": "2", 
     "children": [ 
      { 
       "id": "3" 
      }, 
      { 
       "id": "4" 
      }, 
      { 
       "id": "5", 
       "children": [ 
        { 
         "id": "6" 
        }, 
        { 
         "id": "7", 
         "children": [ 
          { 
           "id": "8" 
          }, 
          { 
           "id": "9" 
          } 
         ] 
        }, 
        { 
         "id": "10" 
        } 
       ] 
      }, 
      { 
       "id": "11" 
      }, 
      { 
       "id": "12" 
      } 
     ] 
    }, 
    { 
     "id": "13" 
    }, 
    { 
     "id": "14" 
    } 
] 
} 

我需要能够通过id和任何子项获取任何“项目”。例如。起初,我试过的grep:

var returnedData = $.grep(obj.items, function(element, index){return element.id == "2"; 
}); 

这对项目工作很大ID为== 2,但完全失败,当我试图获得element.id ==“7”

任何援助将不胜感激。提前致谢。

回答

4

你可以做一个递归函数在数据搜索:

function find(source, id) 
{ 
    for (key in source) 
    { 
     var item = source[key]; 
     if (item.id == id) 
      return item; 

     // Item not returned yet. Search its children by recursive call. 
     if (item.children) 
     { 
      var subresult = find(item.children, id); 

      // If the item was found in the subchildren, return it. 
      if (subresult) 
       return subresult; 
     } 
    } 
    // Nothing found yet? return null. 
    return null; 
} 

// In the root object, the array of items is called 'items', so we pass in 
// data.items to look into. The root object itself doesn't seem to have an id anyway. 
var result = find(data.items, 7); 

// Show the name of item 7, if it had one... 
alert(result.name); 

演示:http://jsfiddle.net/rj26H/

在此功能中我只是环绕在对象,所以它有点冗长。您也可以使用$ .grep来执行搜索并使代码变小一些。无论如何,诀窍是搜索所有的孩子,如果该项目没有在主级别找到。显然grep不能以递归的方式工作。

+0

由于在表面上,这看起来不错。需要在我的脚本中进行测试,但是非常感谢您的快速响应。 – user831839

+0

@GolezTrol这真的很奇怪。对我来说工作很好:http://jsfiddle.net/rj26H/4/ –

+0

@ArtemPetrosian不小心,但如果第6项会有孩子,那么你会看到你的提议打破了代码:http://jsfiddle.net/ rj26H/6 /如果递归调用不返回一个项目,让for循环继续(所以不要调用return)是很重要的。 – GolezTrol

1

试试这个:

var id = 7; 
var data = {"items": [{"id": "d1"},{"id": "2","children": [{"id": "3"},{"id": "7"},{"id": "11"},{"id": "12"}]}]}; 
function search(values) { 
    $.each(values, function(i, v) { 
     if (v.id == id) { 
      console.log('found', v); 
      return false; 
     } 
     if (v.children) { 
      search(v.children); 
     } 
    }); 
} 
search(data.items); 

Demo Link

+0

这不是因为它是一个例子,它使'foo'或'bar'适当的名字。 – plalx

+0

@plalx函数名称更改 –

+0

紧凑整洁,谢谢您的时间,先生。 – user831839

0

我知道这已经被回答,但我想告诉你如何利用新的新JavaScript 1.7 features来解决这个问题。请注意,如果不支持生成器,也可以使用相同的方法,但代码会更长。

//Returns an iterator that knows how to walk a tree 
function treeIterator(root, childGetter, childCountGetter) { 
    let stack = [root], node; 

    while (node = stack.pop()) { 
     yield node; 

     for (let i = childCountGetter(node); i--;) stack.push(childGetter(node, i)); 
    } 
} 

//Our custom search function 
function findNodeById(tree, id) { 
    let it = treeIterator(tree, 
     function (node, i) { return node.children[i]; }, 
     function (node) { return node.children? node.children.length : 0; } 
    ); 

    for (let node in it) if (node.id === id) return node; 

    return null; 
} 

var tree = { 
    id: 'root', 
    children: [ 
     { id: 'a' }, 
     { 
      id: 'b', 
      children: [ 
       { id: 'b1' }, 
       { id: 'b2' } 
      ] 
     }, 
     { id: 'c' } 
    ] 
}; 

findNodeById(tree, 'b1'); //Object { id="b1"} 

请注意,您还可以设置__iterator__上的数据结构,使得需要遍历这个数据结构,功能不必知道实现细节。

tree.__iterator__ = treeIterator.bind(null, tree, 
    function (node, i) { return node.children[i]; }, 
    function (node) { return node.children? node.children.length : 0; } 
); 

然后findNodeById功能可以是:

function findNodeById(tree, id) { 
    for (let node in it) if (node.id === id) return node; 
    return null; 
}