在JavaScript中递归解析JSON树

时间:2017-07-19 21:02:49

标签: javascript json recursion

我一直坚持认为JS中的一个简单问题。我想要做的是我有一个未知的深度JSON,如此:

"A": {
        "B": {
            "e": "",
            "f": {
                "g": "",
                "h": ""
            },
            "C": {
                "i": "",
                "j": "",
                "k": "",
                "l": ""
            },
            "D": {
                "m": "",
                "n": "",
                "o": "",
                "p": ""
            }...

json可以是任何级别的深度。我想要实现的是为每个元素创建一个祖先数组+本身,所以对于“p”,它将是["A", "B", "D", "p"]

我试过像这样使用递归:

build(json, '', []);


function build(json, path, assets){
for (var elem in json) {
  if(json.hasOwnProperty(elem)){
    if(json[elem] == 0){
        assets.push(elem);

          //do stuff with the array


       assets.pop();

      } else {
        var parent = path + '/' + elem;
        assets.push(parent);
        build(json[elem], parent, assets);
        return; 
      }
    }
   }
  }

这是该函数的简化版本,该部分无法正常工作。我背后的想法是遍历每个元素,如果它没有子元素,我追加当前元素并使用它(我不需要保留数组,仅用于该用途)如果它有子元素,我追加当前元素元素并以递归方式为当前元素调用该方法。

解决方案一直有效,直到达到第二级,因此对于“e”,“f”,“C”,“D”它会正确生成,但在去孩子之前会停止。

我错过了什么?

4 个答案:

答案 0 :(得分:0)

我无法完全遵循您的代码,所以我只是从头开始编写解决方案。

值得注意的是,我不确定== 0检查在您的代码中做了什么(可能与我的typeof(...) !== 'object'相同?),我不明白assetspath是有意义的。

var obj = {
  "A": {
    "B": {
      "e": "",
      "f": {
        "g": "",
        "h": ""
      },
      "C": {
        "i": "",
        "j": "",
        "k": "",
        "l": ""
      },
      "D": {
        "m": "",
        "n": "",
        "o": "",
        "p": ""
      },
    }
  }
};

function getPaths(obj, sofar) {
  if (sofar === undefined) {
    sofar = [];
  }

  // Leaf node, just return the path
  if (typeof(obj) !== 'object') {
    return [sofar];
  }

  // Interior node
  var paths = [];
  Object.keys(obj).forEach(function (k) {
    // For each child, recurse and concat
    paths = paths.concat(getPaths(obj[k], sofar.concat([k])));
  });

  return paths;
}

console.log(getPaths(obj));

// Output:
// [ [ 'A', 'B', 'e' ],
//   [ 'A', 'B', 'f', 'g' ],
//   [ 'A', 'B', 'f', 'h' ],
//   [ 'A', 'B', 'C', 'i' ],
//   [ 'A', 'B', 'C', 'j' ],
//   [ 'A', 'B', 'C', 'k' ],
//   [ 'A', 'B', 'C', 'l' ],
//   [ 'A', 'B', 'D', 'm' ],
//   [ 'A', 'B', 'D', 'n' ],
//   [ 'A', 'B', 'D', 'o' ],
//   [ 'A', 'B', 'D', 'p' ] ]

答案 1 :(得分:0)

您可以为受访节点使用数组,并将其用作结果的一部分。



function getPath(object, path) {
    path = path || [];
    Object.keys(object).forEach(function (key) {
        if (object[key] && typeof object[key] === 'object') {
            return getPath(object[key], path.concat(key));
        }
        console.log(path.concat([key,object[key]]).join('/'));
    });
}

var data = { A: { B: { e: "1", f: { g: "2", h: "3" }, C: { i: "4", j: "5", k: "6", l: "7" }, D: { m: "8", n: "9", o: "10", p: "11" } } } };
getPath(data);

.as-console-wrapper { max-height: 100% !important; top: 0; }




答案 2 :(得分:0)

从代码中删除return语句使它对我有用。

https://jsbin.com/deqelaj/edit?html,js,console

var assets = [];

function build(json, path, assets){
for (var elem in json) {
  if(json.hasOwnProperty(elem)){
    if(json[elem] == 0){
        assets.push(elem);

          //do stuff with the array


       assets.pop();

      } else {
        var parent = path + '/' + elem;
        assets.push(parent);
        console.log(assets)
        build(json[elem], parent, assets);
      }
    }
   }
  }


var json = {
  "A": {
        "B": {
            "e": "",
            "f": {
                "g": "",
                "h": ""
            },
            "C": {
                "i": "",
                "j": "",
                "k": "",
                "l": ""
            },
            "D": {
                "m": "",
                "n": "",
                "o": "",
                "p": ""
            }
        }
    }
  }


build(json, '', assets);

console.log(assets)

答案 3 :(得分:0)

使用reduceconcat

执行此操作的另一种方法

const build = (data, path = []) =>
  data == null
    ? []
    : Object (data) === data
      ? Object.entries (data) .reduce ((acc, [ k, v ]) =>
          acc.concat (build (v, [ ...path, k ])), [])
      : [ [ ...path, data ] ]

const mydata =
  { A: { B: { e: '1'
            , f: { g: '2'
                 , h: '3' 
                 }
            , C: { i: '4'
                 , j: '5'
                 , k: '6'
                 , l: '7'
                 }
            , D: { m: '8'
                 , n: '9'
                 , o: '10'
                 , p: '11'
                 } 
            }
       }
  }

console.log (build (mydata))
// [ ['A','B','e','1'],
//   ['A','B','f','g','2'],
//   ['A','B','f','h','3'],
//   ['A','B','C','i','4'],
//   ['A','B','C','j','5'],
//   ['A','B','C','k','6'],
//   ['A','B','C','l','7'],
//   ['A','B','D','m','8'],
//   ['A','B','D','n','9'],
//   ['A','B','D','o','10'],
//   ['A','B','D','p','11'] ]