JSON字符串到JS数组

时间:2017-01-14 09:34:31

标签: javascript arrays json multidimensional-array nested

如何将文件夹结构JSON String转换为JS Array。我遵循JSON字符串

   [{ "Name": "A", "ParentName": "Config", "Type": "default" },
{ "Name": "SubA", "ParentName": "A", "Type": "default" },
{ "Name": "SubAFile", "ParentName": "SubA", "Type": "file" },
{ "Name": "B", "ParentName": "Config", "Type": "default" },
{ "Name": "C", "ParentName": "Config", "Type": "default" }]

我想以下列格式制作JS Array对象

   var NewStr = [{
       "name": 'A',
       "id": 'A',
       "icon": 'fa fa-folder',
       "items": [{
           "title": "A",
           "icon": "fa fa-folder",
           "id": "A",
           "items": [{
               "name": "subA",
               "icon": "fa fa-folder",
               "id": "subA",
               "items": [{
                   "title": "SubA",
                   "icon": "fa fa-folder",
                   "id": "SubA",
                   "items": [{
                       "name": "SubAFile",
                       "icon": "fa fa-file"
                   }]
               }]
           }]
       }]
   }, {
       "name": 'B',
       "id": 'b',
       "icon": "fa fa-folder"
   }, {
       "name": 'C',
       "id": 'C',
       "icon": "fa fa-folder"
   }];

注意:我已经包含了ParentName来识别文件夹结构的层次结构。 ID与名称相同。

对此有何建议?

谢谢..

3 个答案:

答案 0 :(得分:1)

首先使用JSON.parse从有效的JSON字符串生成obbject。

  

JSON.parse() 方法解析JSON字符串,构造字符串描述的JavaScript值或对象。可以提供可选的reviver函数,以在返回结果对象之前对其执行转换。

然后,您可以使用迭代方法生成一个树,创建一个具有引用插入或引用的父对象的所需属性的新对象,使用临时对象。

这也适用于未排序和嵌套的项目。



var data = [{ Name: "A", ParentName: "Config", Type: "default" }, { Name: "SubA", ParentName: "A", Type: "default" }, { Name: "SubAFile", ParentName: "SubA", Type: "file" }, { Name: "B", ParentName: "Config", Type: "default" }, { Name: "C", ParentName: "Config", Type: "default" }],
    tree = function (data, root) {
        var r = [], o = {};
        data.forEach(function (a) {
            var temp = { name: a.Name, icon: a.Type === 'file' ? 'fa fa-file' : 'fa fa-folder' };
            if (o[a.Name] && o[a.Name].items) {
                temp.items = o[a.Name].items;
            }
            o[a.Name] = temp;
            if (a.ParentName === root) {
                r.push(temp);
            } else {
                o[a.ParentName] = o[a.ParentName] || {};
                o[a.ParentName].items = o[a.ParentName].items || [];
                o[a.ParentName].items.push(temp);
            }
        });
        return r;
    }(data, 'Config');

console.log(tree);

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




答案 1 :(得分:0)

这么棒的测验!我保证会在几个小时内找到解决方案。你给的是一种“反向二叉树”,就BigO来说,目前的解决方案看起来太难看了。

如果您不介意我会发布草稿preSolution并继续考虑更多正确的方法来提高工作效率并稍后进行编辑。

var tree = {}

function findParent(data, parentName){
    var parentExist = false;

    $.each(data, function(index, value){
        parentExist = (value.name == parentName);

        if(parentExist){
            moveChild(data, index, tree, tree[value.parentName]);
        } else {
            createParent(parentName, tree);
        }
    }
}

function moveChild(collectionIn, child, collectionOut, parent){
    collectionOut[parent].push(collectionIn[child]);
    splice(collectionIn[child], 1);
}

function createParent(parentName, targetTree);

$.each(data, function(index, val){
  findParent(index.parentName);
  
});

提示我要检查:

答案 2 :(得分:0)

您可以使用Map按名称键入节点,并在使用reduce迭代输入时构建树。对于每个节点,如果父节点尚不存在,则创建父节点。发生这种情况时,请记住这个新创建的父项作为树的根:它的子项是您要生成的数组。

这是ES6代码:



// Sample input JSON parsed:
const items = JSON.parse('[{"Name":"A","ParentName":"Config","Type":"default"},{"Name":"new","ParentName":"A","Type":"file"},{"Name":"B","ParentName":"Config","Type":"default"},{"Name":"C","ParentName":"Config","Type":"default"}]');

const arr = items.reduce( ([nodes, root], {Name, ParentName, Type}) => {
    const node = Object.assign({ // create node
        name: Name,
        icon: Type == 'default' ? 'fa fa-folder' : 'fa fa-file'
    }, nodes.get(Name)); // add previously registered children, if any
    const parent = nodes.get(ParentName) || (root = {}); // create parent if not present
    parent.items = (parent.items || []).concat(node); // add current as child
    return [nodes.set(Name, node).set(ParentName, parent), root];
}, [new Map, {}] )[1].items; // start with empty map, return the items of the root

// Output result
console.log(arr);

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




更新问题后更新

在您的问题更新中,所需的输出已更改,具有更多嵌套级别:具有子级的节点现在需要一个中间对象作为子级(具有大多数相同的属性),而子级节点又连接到其自己的{{ 1}}属性。

以下是适用于此目的的ES6代码:



items

function buildTree(folders) {
    const [nodes, root] = folders.reduce( ([nodes, root], {Name, ParentName, Type}) => {
        const node = Object.assign({ // create node
            name: Name,
            id: Name,
            icon: Type == 'default' ? 'fa fa-folder' : 'fa fa-file'
        }, nodes.get(Name)); // add previously registered children, if any
        const parent = nodes.get(ParentName) || (root = {}); // create parent if not present
        parent.items = (parent.items || []).concat(node); // add current as child
        return [nodes.set(Name, node).set(ParentName, parent), root];
    }, [new Map, {}] );
    // To add the extra intermediate levels (requested in updated question):
    nodes.forEach( node => {
        if (node.items) node.items = [{
            title: node.name,
            icon: node.icon,
            id: node.id,
            items: node.items
        }]
    });
    return root.items[0].items;
}    

// Sample JSON data, parsed
const folders = JSON.parse('[{ "Name": "A", "ParentName": "Config", "Type": "default" },{ "Name": "SubA", "ParentName": "A", "Type": "default" },{ "Name": "SubAFile", "ParentName": "SubA", "Type": "file" },{ "Name": "B", "ParentName": "Config", "Type": "default" },{ "Name": "C", "ParentName": "Config", "Type": "default" }]');

const arr = buildTree(folders);

// Output result
console.log(arr);




ES5版本

对于支持ES6很少的浏览器(如IE):



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

function buildTree(folders) {
    var result = folders.reduce(function (acc, obj) {
        var nodes = acc[0];
        var root = acc[1];
        var node = { // create node
            name: obj.Name,
            id: obj.Name,
            icon: obj.Type == 'default' ? 'fa fa-folder' : 'fa fa-file'
        };
        // add previously registered children, if any
        if (nodes[obj.Name]) node.items = nodes[obj.Name].items;
        var parent = nodes[obj.ParentName] || (root = {}); // create parent if not present
        parent.items = (parent.items || []).concat(node); // add current as child
        nodes[obj.Name] = node;
        nodes[obj.ParentName] = parent;
        return [nodes, root];
    }, [{}, {}] );
    // To add the extra intermediate levels (requested in updated question):
    for (var name in result[0]) {
        var node = result[0][name];
        if (node.items) node.items = [{
            title: node.name,
            icon: node.icon,
            id: node.id,
            items: node.items
        }];
    }
    return result[1].items[0].items;
}    

// Sample JSON data, parsed
var folders = JSON.parse('[{ "Name": "A", "ParentName": "Config", "Type": "default" },{ "Name": "SubA", "ParentName": "A", "Type": "default" },{ "Name": "SubAFile", "ParentName": "SubA", "Type": "file" },{ "Name": "B", "ParentName": "Config", "Type": "default" },{ "Name": "C", "ParentName": "Config", "Type": "default" }]');

var arr = buildTree(folders);

// Output result
console.log(arr);