2014-05-04 8 views
0

J'ai le code JSON valide suivant. Il décrit une structure arborescente:JSON imbriqué find item

{ 
"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" 
    } 
] 
} 

Je dois être en mesure d'obtenir l'un des « éléments » par identifiant et l'un des éléments de l'enfant. Par exemple. Dans un premier temps j'ai essayé grep:

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

Cela fonctionnait très bien pour le point avec id == 2 mais échoue complètement lorsque je tente d'obtenir element.id == « 7 »

Toute aide serait appréciée. Merci d'avance.

Répondre

4

Vous pouvez faire une fonction récursive pour rechercher dans les données:

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); 

Démo: http://jsfiddle.net/rj26H/

Dans cette fonction que je viens en boucle sur l'objet, de sorte que son un peu plus bavard. Vous pourriez probablement aussi utiliser $ .grep pour faire la recherche et rendre le code un peu plus petit. Quoi qu'il en soit, l'astuce consiste à rechercher tous les enfants si l'objet n'est pas trouvé au niveau principal. Apparemment, grep ne fonctionne pas de manière récursive.

+0

Merci à la surface ce semble bon. Besoin de tester dans le contexte de mon script, mais j'apprécie vraiment votre réponse rapide. – user831839

+0

@GolezTrol C'est vraiment étrange. Fonctionne bien pour moi: http://jsfiddle.net/rj26H/4/ –

+0

@ArtemPetrosian Accidentellement, mais si le point 6 aurait des enfants, alors vous verrez que votre proposition brise le code: http://jsfiddle.net/ rj26H/6/Il est important de laisser la boucle for continuer (donc n'appelez pas return) si l'appel récursif ne renvoie pas un élément. – GolezTrol

1

Essayez ceci:

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

Ce n'est pas parce que c'est un exemple qu'il fait des noms appropriés 'foo' ou' bar'. – plalx

+0

@plalx nom de la fonction a changé –

+0

Compact et soigné, merci pour votre temps, monsieur. – user831839

0

Je sais que cela a été déjà répondu, mais je voulais montrer comment vous pouvez tirer parti de la nouvelle la nouvelle JavaScript 1.7 features pour résoudre ce problème. Veuillez noter que la même approche aurait pu être utilisée sans support pour les générateurs, mais le code aurait été plus long.

//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"} 

Notez que vous pouvez également définir la __iterator__ sur la structure de données afin que les fonctions qui doivent itérer sur cette structure de données ne doivent pas connaître les détails de mise en œuvre.

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

Ensuite, la fonction findNodeById peut être:

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