Пройдите все узлы дерева объектов JSON с помощью JavaScript

Я хотел бы пересечь дерево объектов JSON, но не могу найти для этого никакой библиотеки. Это не кажется трудным, но кажется, что он изобретает колесо.

В XML есть так много руководств, показывающих, как перемещаться по дереву XML с помощью DOM: (

Ответ 1

Если вы считаете, что jQuery является overkill для такой примитивной задачи, вы можете сделать что-то вроде этого:

//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 all... no magic, no bloated framework
traverse(o,process);

Ответ 2

Объект JSON - это просто объект Javascript. Вот что на самом деле означает JSON: JavaScript Object Notation. Таким образом, вы будете проходить через объект JSON, но в целом вы будете выбирать "обходить" объект Javascript.

В ES2017 вы бы сделали:

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

Вы всегда можете написать функцию, чтобы рекурсивно спускаться в объект:

function traverse(jsonObj) {
    if( jsonObj !== null && 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
    }
}

Это должно быть хорошей отправной точкой. Я настоятельно рекомендую использовать современные методы javascript для таких вещей, поскольку они значительно облегчают написание такого кода.

Ответ 3

function traverse(o ) {
    for (i in o) {
        if (!!o[i] && typeof(o[i])=="object") {
            console.log(i, o[i])
            traverse(o[i] );
        }
    }
}

Ответ 4

Там есть новая библиотека для перемещения данных JSON с JavaScript, которая поддерживает множество различных случаев использования.

https://npmjs.org/package/traverse

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

Он работает со всеми видами объектов JavaScript. Он даже обнаруживает циклы.

Он также предоставляет путь для каждого node.

Ответ 5

Зависит от того, что вы хотите сделать. Здесь приведен пример перемещения дерева объектов JavaScript, печати ключей и значений по мере их появления:

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

Ответ 6

Если вы просматриваете фактическую строку JSON, вы можете использовать функцию reviver.

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

При перемещении объекта:

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

РЕДАКТИРОВАТЬ: все приведенные ниже примеры в этом ответе были отредактированы, чтобы включить новую переменную пути, полученную из итератора в соответствии с @supersan request. Переменная path - это массив строк, где каждая строка в массиве представляет каждый ключ, к которому был получен доступ, чтобы получить результирующее повторяющееся значение из исходного исходного объекта. Переменная пути может быть передана в функцию/метод lodash get. Или вы можете написать свою собственную версию lodash get, которая обрабатывает только массивы примерно так:

function get (object, path) {
  return path.reduce((obj, pathItem) => obj ? obj[pathItem] : undefined, object);
}

const example = {a: [1,2,3], b: 4, c: { d: ["foo"] }};
// these paths exist on the object
console.log(get(example, ["a", "0"]));
console.log(get(example, ["c", "d", "0"]));
console.log(get(example, ["b"]));
// these paths do not exist on the object
console.log(get(example, ["e", "f", "g"]));
console.log(get(example, ["b", "f", "g"]));

Ответ 8

Я хотел использовать идеальное решение @TheHippo в анонимной функции без использования функций процесса и триггера. Следующие работали для меня, как для меня, так и для начинающих программистов.

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

Ответ 9

Большинство движков Javascript не оптимизируют хвостовую рекурсию (это может быть не проблема, если ваш JSON не глубоко вложен), но я обычно ошибаюсь на стороне осторожности и вместо этого выполняю итерацию, например.

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)

Ответ 10

Мой 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;
};

Вход 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": []
                    }
                ]
            }
       ]
   }
]

Вызов функции:

callback_func(inp_json);

Выход по моей потребности:

["output/f1/ver"]

Ответ 11

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>

Ответ 12

Лучшим решением для меня было следующее:

простой и без использования каких-либо фреймворков

    var doSomethingForAll = function (arg) {
       if (arg != undefined && arg.length > 0) {
            arg.map(function (item) {
                  // do something for item
                  doSomethingForAll (item.subitem)
             });
        }
     }

Ответ 13

Вы можете получить все ключи/значения и сохранить иерархию с помощью этого

// 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')

Это модификация (fooobar.com/questions/49508/...)

Ответ 14

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

Ответ 15

Я создал библиотеку для перемещения и редактирования глубоко вложенных объектов JS. Ознакомьтесь с API здесь: https://github.com/dominik791

Вы также можете играть в библиотеке интерактивно с помощью демонстрационного приложения: https://dominik791.github.io/obj-traverse-demo/

Примеры использования: Вы всегда должны иметь корневой объект, который является первым параметром каждого метода:

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

Второй параметр всегда является именем свойства, которое содержит вложенные объекты. В приведенном выше случае это будет 'children'.

Третий параметр - это объект, который вы используете для поиска объектов/объектов, которые вы хотите найти/изменить/удалить. Например, если вы ищете объект с id равным 1, то вы передадите { id: 1} в качестве третьего параметра.

И вы можете:

  • findFirst(rootObj, 'children', { id: 1 }), чтобы найти первый объект   с id === 1
  • findAll(rootObj, 'children', { id: 1 }), чтобы найти все объекты   с id === 1
  • findAndDeleteFirst(rootObj, 'children', { id: 1 }) для удаления первого объекта соответствия
  • findAndDeleteAll(rootObj, 'children', { id: 1 }) для удаления всех соответствующих объектов

replacementObj используется как последний параметр в двух последних методах:

  • findAndModifyFirst(rootObj, 'children', { id: 1 }, { id: 2, name: 'newObj'}) изменить первый найденный объект с помощью id === 1 на { id: 2, name: 'newObj'}
  • findAndModifyAll(rootObj, 'children', { id: 1 }, { id: 2, name: 'newObj'}), чтобы изменить все объекты с помощью id === 1 на { id: 2, name: 'newObj'}