Parcourir tous les noeuds D'une arborescence D'objets JSON avec JavaScript

j'aimerais parcourir un arbre d'objets JSON, mais je ne peux pas trouver de bibliothèque pour ça. Cela ne semble pas difficile, mais c'est comme réinventer la roue.

en XML il y a tellement de tutoriels montrant comment parcourir un arbre XML avec DOM: (

126
demandé sur Patsy Issa 2009-04-06 22:45:16

15 réponses

si vous pensez que jQuery est une sorte de overkill pour une telle tâche primitive, vous pourriez faire quelque chose comme cela:

//your object
var o = { 
    foo:"bar",
    arr:[1,2,3],
    subo: {
        foo2:"bar2"
    }
};

//called with every property and its value
function process(key,value) {
    console.log(key + " : "+value);
}

function traverse(o,func) {
    for (var i in o) {
        func.apply(this,[i,o[i]]);  
        if (o[i] !== null && typeof(o[i])=="object") {
            //going one step down in the object tree!!
            traverse(o[i],func);
        }
    }
}

//that's all... no magic, no bloated framework
traverse(o,process);
195
répondu TheHippo 2017-03-16 16:27:14

un objet JSON est simplement un objet Javascript. C'est en fait ce que JSON signifie: JavaScript Object Notation. Ainsi, vous traverseriez un objet JSON, mais vous choisiriez de "traverser" un objet Javascript en général.

dans ES2017 vous feriez:

Object.entries(jsonObj).forEach(([key, value]) => {
    // do something with key and val
});

vous pouvez toujours écrire une fonction pour descendre récursivement dans l'objet:

function traverse(jsonObj) {
    if( typeof jsonObj == "object" ) {
        Object.entries(jsonObj).forEach(([key, value]) => {
            // key is either an array index or object key
            traverse(value);
        });
    }
    else {
        // jsonObj is a number or string
    }
}

Cela devrait être un bon point de départ. Je recommande vivement d'utiliser méthodes javascript modernes pour de telles choses, car ils rendent l'écriture de ce code beaucoup plus facile.

52
répondu Eli Courtwright 2018-03-17 23:07:58
function traverse(o ) {
    for (i in o) {
        if (!!o[i] && typeof(o[i])=="object") {
            console.log(i, o[i])
            traverse(o[i] );
        }
    }
}
29
répondu tejas 2018-01-24 17:02:19

Il ya une nouvelle bibliothèque pour traverser les données JSON avec JavaScript qui prend en charge de nombreux cas d'utilisation différents.

https://npmjs.org/package/traverse

https://github.com/substack/js-traverse

Il fonctionne avec toutes sortes d'objets JavaScript. Il détecte même les cycles.

il fournit le chemin de chaque noeud, aussi.

27
répondu Ben Atkin 2012-12-27 23:31:50

Dépend de ce que vous voulez faire. Voici un exemple de traversée D'un arbre D'objets JavaScript, en imprimant des clés et des valeurs comme il va:

function js_traverse(o) {
    var type = typeof o 
    if (type == "object") {
        for (var key in o) {
            print("key: ", key)
            js_traverse(o[key])
        }
    } else {
        print(o)
    }
}

js> foobar = {foo: "bar", baz: "quux", zot: [1, 2, 3, {some: "hash"}]}
[object Object]
js> js_traverse(foobar)                 
key:  foo
bar
key:  baz
quux
key:  zot
key:  0
1
key:  1
2
key:  2
3
key:  3
key:  some
hash
11
répondu Brian Campbell 2009-04-06 19:06:59

si vous traversez un JSON réel chaîne de caractères alors vous pouvez utiliser une fonction de réveil.

function traverse (json, callback) {
  JSON.parse(json, function (key, value) {
    if (key !== '') {
      callback.call(this, key, value)
    }
    return value
  })
}

traverse('{"a":{"b":{"c":{"d":1}},"e":{"f":2}}}', function (key, value) {
  console.log(arguments)
})

lors de la traversée d'un objet:

function traverse (obj, callback, trail) {
  trail = trail || []

  Object.keys(obj).forEach(function (key) {
    var value = obj[key]

    if (Object.getPrototypeOf(value) === Object.prototype) {
      traverse(value, callback, trail.concat(key))
    } else {
      callback.call(obj, key, value, trail)
    }
  })
}

traverse({a: {b: {c: {d: 1}}, e: {f: 2}}}, function (key, value, trail) {
  console.log(arguments)
})
7
répondu David Lane 2015-10-08 17:25:10

je voulais utiliser la solution parfaite de @Thippo dans une fonction anonyme, sans utilisation de processus et de fonctions de déclenchement. Ce qui suit a fonctionné pour moi, le partage pour les programmeurs novices comme moi.

(function traverse(o) {
    for (var i in o) {
        console.log('key : ' + i + ', value: ' + o[i]);

        if (o[i] !== null && typeof(o[i])=="object") {
            //going on step down in the object tree!!
            traverse(o[i]);
        }
    }
  })
  (json);
4
répondu Raf 2015-08-11 15:28:45

la plupart des moteurs Javascript n'optimisent pas la recursion de la queue (ce n'est peut-être pas un problème si votre JSON n'est pas profondément imbriqué), mais je me trompe généralement sur le côté de la prudence et faire itération à la place, par exemple

function traverse(o, fn) {
    const stack = [o]

    while (stack.length) {
        const obj = stack.shift()

        Object.keys(obj).forEach((key) => {
            fn(key, obj[key], obj)
            if (obj[key] instanceof Object) {
                stack.unshift(obj[key])
                return
            }
        })
    }
}

const o = {
    name: 'Max',
    legal: false,
    other: {
        name: 'Maxwell',
        nested: {
            legal: true
        }
    }
}

const fx = (key, value, obj) => console.log(key, value)
traverse(o, fx)
2
répondu Max 2016-10-14 22:44:43

pour une nouvelle façon de le faire si vous ne vous gênez pas de laisser tomber IE et principalement en soutenant les navigateurs plus actuels (cochez table es6 de kangax pour la compatibilité). Vous pouvez utiliser es2015 générateurs pour cela. J'ai mis à jour la réponse de @TheHippo en conséquence. Bien sûr, si vous voulez vraiment le soutien D'IE, vous pouvez utiliser le babel JavaScript transpiler.

//your object
var o = { 
    foo:"bar",
    arr:[1,2,3],
    subo: {
        foo2:"bar2"
    }
};

function* traverse(o,func) {
    for (var i in o) {
        yield [i,o[i]]; 
        if (o[i] !== null && typeof(o[i])=="object") {
            //going one step down in the object tree!!
            yield* traverse(o[i],func);
        }
    }
}

//that's all... no magic, no bloated framework
for(var [key, value] of traverse(o)) {
  console.log(key, value);
}

Si vous voulez seulement propres propriétés énumérables (essentiellement non-prototype chaîne propriétés) Vous pouvez le changer pour itérer en utilisant Object.keys et a for...of boucle à la place:

//your object
var o = { 
    foo:"bar",
    arr:[1,2,3],
    subo: {
        foo2:"bar2"
    }
};

function* traverse(o,func) {
    for (var i of Object.keys(o)) {
        yield [i,o[i]]; 
        if (o[i] !== null && typeof(o[i])=="object") {
            //going one step down in the object tree!!
            yield* traverse(o[i],func);
        }
    }
}

//that's all... no magic, no bloated framework
for(var [key, value] of traverse(o)) {
  console.log(key, value);
}
1
répondu John 2017-08-11 06:33:11

Mon Script:

op_needed = [];
callback_func = function(val) {
  var i, j, len;
  results = [];
  for (j = 0, len = val.length; j < len; j++) {
    i = val[j];
    if (i['children'].length !== 0) {
      call_func(i['children']);
    } else {
      op_needed.push(i['rel_path']);
    }
  }
  return op_needed;
};

Input JSON:

[
    {
        "id": null, 
        "name": "output",   
        "asset_type_assoc": [], 
        "rel_path": "output",
        "children": [
            {
                "id": null, 
                "name": "output",   
                "asset_type_assoc": [], 
                "rel_path": "output/f1",
                "children": [
                    {
                        "id": null, 
                        "name": "v#",
                        "asset_type_assoc": [], 
                        "rel_path": "output/f1/ver",
                        "children": []
                    }
                ]
            }
       ]
   }
]

Appel De Fonction:

callback_func(inp_json);

sortie selon mon besoin:

["output/f1/ver"]
0
répondu Mohideen ibn Mohammed 2017-02-28 13:40:06

var test = {
    depth00: {
        depth10: 'string'
        , depth11: 11
        , depth12: {
            depth20:'string'
            , depth21:21
        }
        , depth13: [
            {
                depth22:'2201'
                , depth23:'2301'
            }
            , {
                depth22:'2202'
                , depth23:'2302'
            }
        ]
    }
    ,depth01: {
        depth10: 'string'
        , depth11: 11
        , depth12: {
            depth20:'string'
            , depth21:21
        }
        , depth13: [
            {
                depth22:'2201'
                , depth23:'2301'
            }
            , {
                depth22:'2202'
                , depth23:'2302'
            }
        ]
    }
    , depth02: 'string'
    , dpeth03: 3
};


function traverse(result, obj, preKey) {
    if(!obj) return [];
    if (typeof obj == 'object') {
        for(var key in obj) {
            traverse(result, obj[key], (preKey || '') + (preKey ? '[' +  key + ']' : key))
        }
    } else {
        result.push({
            key: (preKey || '')
            , val: obj
        });
    }
    return result;
}

document.getElementById('textarea').value = JSON.stringify(traverse([], test), null, 2);
<textarea style="width:100%;height:600px;" id="textarea"></textarea>
0
répondu seung 2017-11-24 12:34:54

la meilleure solution pour moi était la suivante:

simple et sans utiliser de cadre

    var doSomethingForAll = function (arg) {
       if (arg != undefined && arg.length > 0) {
            arg.map(function (item) {
                  // do something for item
                  doSomethingForAll (item.subitem)
             });
        }
     }
-1
répondu Asqan 2015-07-31 08:06:57

vous pouvez obtenir toutes les clés / valeurs et préserver la hiérarchie avec ce

// get keys of an object or array
function getkeys(z){
  var out=[]; 
  for(var i in z){out.push(i)};
  return out;
}

// print all inside an object
function allInternalObjs(data, name) {
  name = name || 'data';
  return getkeys(data).reduce(function(olist, k){
    var v = data[k];
    if(typeof v === 'object') { olist.push.apply(olist, allInternalObjs(v, name + '.' + k)); }
    else { olist.push(name + '.' + k + ' = ' + v); }
    return olist;
  }, []);
}

// run with this
allInternalObjs({'a':[{'b':'c'},{'d':{'e':5}}],'f':{'g':'h'}}, 'ob')

C'est une modification ( https://stackoverflow.com/a/25063574/1484447 )

-1
répondu Ricky 2017-05-23 12:34:45
             var localdata = [{''}]// Your json array
              for (var j = 0; j < localdata.length; j++) 
               {$(localdata).each(function(index,item)
                {
                 $('#tbl').append('<tr><td>' + item.FirstName +'</td></tr>);
                 }
-1
répondu RAJ KADAM 2016-06-21 12:27:47

j'ai créé une bibliothèque pour parcourir et éditer de profonds objets js imbriqués. Consultez L'API ici: https://github.com/dominik791

vous pouvez également jouer avec la bibliothèque de façon interactive en utilisant l'application de démonstration: https://dominik791.github.io/obj-traverse-demo /

Exemples d'utilisation: Vous devriez toujours avoir l'objet root qui est le premier paramètre de chaque méthode:

var rootObj = {
  name: 'rootObject',
  children: [
    {
      'name': 'child1',
       children: [ ... ]
    },
    {
       'name': 'child2',
       children: [ ... ]
    }
  ]
};

le second paramètre est toujours le nom de la propriété qui détient les objets imbriqués. Dans le cas ci-dessus, ce serait 'children' .

Le troisième paramètre est un objet que vous utilisez pour trouver l'objet/les objets que vous souhaitez rechercher/modifier/supprimer. Par exemple, si vous cherchez un objet avec un id égal à 1, vous passerez { id: 1} comme troisième paramètre.

et vous pouvez:

  1. findFirst(rootObj, 'children', { id: 1 }) pour trouver objet avec id === 1
  2. findAll(rootObj, 'children', { id: 1 }) pour trouver tous les objets avec id === 1
  3. findAndDeleteFirst(rootObj, 'children', { id: 1 }) supprimer le premier objet correspondant
  4. findAndDeleteAll(rootObj, 'children', { id: 1 }) pour supprimer tous les objets correspondants

replacementObj est utilisé comme dernier paramètre dans deux dernières méthodes:

  1. findAndModifyFirst(rootObj, 'children', { id: 1 }, { id: 2, name: 'newObj'}) pour remplacer le premier objet trouvé par id === 1 par { id: 2, name: 'newObj'}
  2. findAndModifyAll(rootObj, 'children', { id: 1 }, { id: 2, name: 'newObj'}) pour changer tous les objets avec id === 1 en { id: 2, name: 'newObj'}
-1
répondu dominik791 2017-02-14 13:50:38