Home » Javascript » Create a directory tree from dropbox api delta using the paths

Create a directory tree from dropbox api delta using the paths

Posted by: admin November 1, 2017 Leave a comment

Questions:

I found the question How to convert a file path into treeview?, but I’m not sure how to get the desired result in JavaScript:

I’m trying to turn an array of paths into a JSON tree:

 var paths = [
        "/org/openbmc/UserManager/Group",
        "/org/stackExchange/StackOverflow",
        "/org/stackExchange/StackOverflow/Meta",
        "/org/stackExchange/Programmers",
        "/org/stackExchange/Philosophy",
        "/org/stackExchange/Religion/Christianity",
        "/org/openbmc/records/events",
        "/org/stackExchange/Religion/Hinduism",
        "/org/openbmc/HostServices",
        "/org/openbmc/UserManager/Users",
        "/org/openbmc/records/transactions",
        "/org/stackExchange/Religion/Islam",
        "/org/openbmc/UserManager/Groups",
        "/org/openbmc/NetworkManager/Interface"
    ];

I want to have json structure like below using the folder paths.

        var xyz = [{
            "path": "photos",
            "name": "photos",
            "children": [
              {
                "path": "photos/summer",
                "name": "summer",
                "children": [
                  {
                    "path": "photos/summer/june",
                    "name": "june",
                    "children": [
                      {
                        "path": "photos/summer/june/windsurf",
                        "name": "windsurf",
                      }
                    ]
                  }
                ]
              },
              {
                "path": "photos/winter",
                "name": "winter",
                "children": [
                  {
                    "path": "photos/winter/january",
                    "name": "january",
                    "children": [
                      {
                        "path": "photos/winter/january/ski",
                        "name": "ski",
                      },
                      {
                        "path": "photos/winter/january/snowboard",
                        "name": "snowboard",
                      }
                    ]
                  }
                ]
              }
            ]
    }];

I have used below function but it’s not working

var parsePathArray = function(paths) {
var parsed = [];
for (var i = 0; i < paths.length; i++) {
    var position = parsed;
    var split = paths[i].split('/');
    for (var j = 0; j < split.length; j++) {
        if (split[j] !== "") {
            if (typeof position[split[j]] === 'undefined')
                position[split[j]] = {};
            position.children = [position[split[j]]];
            position.name = split[j];
            position = position[split[j]];

        }
    }
}
return parsed;
}
Answers:

Disclaimer: I wrote this answer because it’s a fun exercise. I’m still disappointed in you for not trying and not taking the time to explain what it is you don’t understand…


I didn’t follow your exact format so you’ll have to try to understand how it’s done instead of being able to copy the code and leave 🙂

I’ll touch upon each step briefly to not risk explaining what you already know.

Step 1:

Go from a list of strings to a list of arrays:

["a/1", "a/2", "b/1"] -> [["a", "1"], ["a", "2"], ["b", "1"]]

We use String.prototype.slice to remove the prepended “/” and String.prototype.split with your folder delimiter to convert to an array: path.split("/")

Step 2

Loop over each folder and add the folder to an object.

[["a", "1"], ["a", "2"], ["b", "1"]] -> { a: { 1: {}, 2: {} }, b: { 1: {} } }

We use a reducer that accesses an object using bracket notation obj[key] instantiating new folder objects and returning the deepest location along the way.

Step 3

Recursively loop over the keys of your object and convert to a specified format:

{ a: { 1: { } } -> { name: "a", path: [], children: [ /* ... */ ] }

We take a list of keys, which are folder names, using Object.keys. Recursively call for each nested object.


Please, update your answer with the specific step you have trouble with which allows others to help as well, and me to describe the step in more detail.

const pathStrings = ["/org/openbmc/UserManager/Group", "/org/stackExchange/StackOverflow", "/org/stackExchange/StackOverflow/Meta", "/org/stackExchange/Programmers", "/org/stackExchange/Philosophy", "/org/stackExchange/Religion/Christianity", "/org/openbmc/records/events", "/org/stackExchange/Religion/Hinduism", "/org/openbmc/HostServices", "/org/openbmc/UserManager/Users", "/org/openbmc/records/transactions", "/org/stackExchange/Religion/Islam", "/org/openbmc/UserManager/Groups", "/org/openbmc/NetworkManager/Interface"];

const paths = pathStrings
    .map(str => str.slice(1))       // remove first "/"
    .map(str => str.split("/"));

// Mutates map!
const mergePathInToMap = (map, path) => {
    path.reduce(
        (loc, folder) => (loc[folder] = loc[folder] || {}, loc[folder]),
        map      
    );

    return map;
};

// Folder structure as { folderName: folderContents }
const folderMap = paths.reduce(mergePathInToMap, {});

// Go from 
//   { folderName: folderContents }
// to a desired format like 
//   { name: folderName, children: [contents] }
const formatStructure = (folder, path) => {
    return Object
        .keys(folder)
        .map(k => ({ 
            name: k,
            path: path,
            children: formatStructure(folder[k], path.concat(k))
        }))
    
}

console.log(
    JSON.stringify(
        formatStructure(folderMap, []),
        null,
        2
    )
)
.as-console-wrapper { min-height: 100% }