-1

I need to convert an array of string paths into nested JSON without duplicates.

I'm trying to build a JSON file from an array of string paths. When building the JSON I'd like duplicate folder names to be nested (i.e. "catalog" would have "product" and "non-product" as children). Each object would have a name and an optional children array.

let paths = [
  "catalog/product/category/sub-category/page",
  "catalog/non-product/page"
];

let pages = {};
paths.forEach(path => {
  let levels = path.split("/");
  let file = levels.pop();

  // iterate over each path and build JSON

});

console.log(pages);

Ideal output of pages would be:

{
    "name": "catalog",
    "children": [
        {
            "name": "product",
            "children" : [
                {
                    "name": "category",
                    "children": [
                        {
                            "name": "sub-category",
                            "children": [
                                {
                                    "name": "page",
                                }
                            ]
                        }
                    ]
                }
            ]
        },
        {
            "name" : "non-product",
            "children" : [
                {
                    "name" : "page"
                }
            ]
        }
    ]
}
Ray
  • 225
  • 2
  • 7
  • What have you tried so far to solve this on your own? – Andreas Feb 05 '21 at 09:09
  • _"// iterate over each path and build JSON"_ - If it's not a string it's not [JSON](https://www.json.org/json-en.html). The expected result is an object. – Andreas Feb 05 '21 at 09:10
  • @Andreas I spent a few hours with ```reduce``` but could not get the nesting correct – Ray Feb 05 '21 at 09:13
  • I was trying to adapt [this solution](https://stackoverflow.com/questions/49704201/parse-string-of-file-path-to-json-object) but I could not get it to work for paths with more than two nested folders – Ray Feb 05 '21 at 09:18

1 Answers1

1

Here is a sample for building a directory tree:

const paths = [
   "catalog/product/category/sub-category/page",
   "catalog/non-product/page",
   "test/2"
];

const directoryTree = {
   name: '/',
   children: []
};

paths.forEach(path => {
   const directorySegments = path.split("/");

   let currentDirectory = directoryTree;

   directorySegments.forEach(segment => {
      const child = currentDirectory.children.find(path => path.name.toLowerCase() === segment.toLowerCase());

      if (child !== undefined) {
         currentDirectory = child;
      }
      else {
         const newDirectory = {
            name: segment,
            children: []
         };

         currentDirectory.children.push(newDirectory);

         currentDirectory = newDirectory;
      }
   });
});

const directoryJSON = JSON.stringify(directoryTree);

If you need to remove the children property for empty directories, you can modify the code as such:

const paths = [
   "catalog/product/category/sub-category/page",
   "catalog/non-product/page",
   "test/2"
];

const directoryTree = {
   name: '/'
};

paths.forEach(path => {
   const directorySegments = path.split("/");

   let currentDirectory = directoryTree;

   directorySegments.forEach(segment => {
      let child;

      if (currentDirectory.children !== undefined) {
         child = currentDirectory.children.find(path => path.name.toLowerCase() === segment.toLowerCase());
      }
      else {
         currentDirectory.children = [];
      }

      if (child !== undefined) {
         currentDirectory = child;
      }
      else {
         const newDirectory = {
            name: segment
         };

         currentDirectory.children.push(newDirectory);

         currentDirectory = newDirectory;
      }
   });
});

const directoryJSON = JSON.stringify(directoryTree);

It will produce the following JSON result:

{
   "name":"/",
   "children":[
      {
         "name":"catalog",
         "children":[
            {
               "name":"product",
               "children":[
                  {
                     "name":"category",
                     "children":[
                        {
                           "name":"sub-category",
                           "children":[
                              {
                                 "name":"page"
                              }
                           ]
                        }
                     ]
                  }
               ]
            },
            {
               "name":"non-product",
               "children":[
                  {
                     "name":"page"
                  }
               ]
            }
         ]
      },
      {
         "name":"test",
         "children":[
            {
               "name":"2"
            }
         ]
      }
   ]
}

As you see, I am using a root directory("/") to hold the tree. You can exclude it if the "catalog" is your root.

zhulien
  • 5,145
  • 3
  • 22
  • 36