2014-05-04 192 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; 
}