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: (
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);
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.
function traverse(o ) {
for (i in o) {
if (!!o[i] && typeof(o[i])=="object") {
console.log(i, o[i])
traverse(o[i] );
}
}
}
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.
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
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)
})
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);
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)
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);
}
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"]
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>
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)
});
}
}
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 )
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>);
}
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:
-
findFirst(rootObj, 'children', { id: 1 })
pour trouver objet avecid === 1
-
findAll(rootObj, 'children', { id: 1 })
pour trouver tous les objets avecid === 1
-
findAndDeleteFirst(rootObj, 'children', { id: 1 })
supprimer le premier objet correspondant -
findAndDeleteAll(rootObj, 'children', { id: 1 })
pour supprimer tous les objets correspondants
replacementObj
est utilisé comme dernier paramètre dans deux dernières méthodes:
-
findAndModifyFirst(rootObj, 'children', { id: 1 }, { id: 2, name: 'newObj'})
pour remplacer le premier objet trouvé parid === 1
par{ id: 2, name: 'newObj'}
-
findAndModifyAll(rootObj, 'children', { id: 1 }, { id: 2, name: 'newObj'})
pour changer tous les objets avecid === 1
en{ id: 2, name: 'newObj'}