javascriptjsonpathname

How best to convert an array of string paths to JSON?


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"
                }
            ]
        }
    ]
}

Solution

  • 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.