Jamie Hutber
Jamie Hutber

Reputation: 28064

Convert json into nested JavaScript Object

I have a json int file that contains any items like below:

Input JSON

{
    "action.button.submit": "Submit"
    "action.button.submitting": "Submitting"
    "buttons.common.add": "Add"
    "buttons.common.reset": "Reset"
    "constants.bom.conditional.or.mandatory.conditional": "Conditional"
    "constants.bom.conditional.or.mandatory.mandatory": "Mandatory"
}

Output

{
   action: {
       button: {
           submit: 'Submit'
           submitting: 'Submitting'
       }
   },
   buttons: {
       common: {
           add: 'Add',
           reset: 'Reset'
       }
   },
   constants: {
      bom: {
         conditional: { 
            or: {
                mandatory:{
                   conditional: 'Conditional',
                   mandatory: 'Mandatory'
               }
            }
         }
      }
   }
}

This was as far as I could get:

newData = {};
Object.keys(data).forEach(item => {
    const splitData = item.split('.');
    splitData.forEach((detail, index) => {
        if(index === 0 && !newData[detail]) newData[detail] = {};
    })
});
console.info(newData)

I would like to take the Input and make it look like the output

Upvotes: 1

Views: 69

Answers (2)

Nenad Vracar
Nenad Vracar

Reputation: 122027

You could use one forEach loop on object entries and then inside split each key on .. After that you can use reduce method on that array of keys to build nested object.

const obj = {
  "action.button.submit": "Submit",
  "action.button.submitting": "Submitting",
  "buttons.common.add": "Add",
  "buttons.common.reset": "Reset",
  "constants.bom.conditional.or.mandatory.conditional": "Conditional",
  "constants.bom.conditional.or.mandatory.mandatory": "Mandatory"
}

const res = {}
Object.entries(obj).forEach(([key, value]) => {
  key.split('.').reduce((r, e, i, a) => {
    return r[e] || (r[e] = (a[i + 1] ? {} : value))
  }, res)
})

console.log(res)

Using Lodash you can do this with _.set method that takes target object, nested key and value.

const obj = {"action.button.submit": "Submit","action.button.submitting": "Submitting","buttons.common.add": "Add","buttons.common.reset": "Reset","constants.bom.conditional.or.mandatory.conditional": "Conditional","constants.bom.conditional.or.mandatory.mandatory": "Mandatory"}

const res = {}
_.forEach(_.entries(obj), ([k, v]) => _.set(res, k, v))
console.log(res)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.js"></script>

Upvotes: 1

Jonas Wilms
Jonas Wilms

Reputation: 138257

You have to recursively traverse deep into the resulting object:

function parse(obj) {
  const root = {};

  for(const [key, value] of Object.entries(obj)) {
    const parts = key.split(".");
    const parent = parts.slice(0, -1).reduce((acc, part) => acc[part] || (acc[part] = {}), root);
    parent[parts.pop()] = value;
  }

  return root;
}

Upvotes: 1

Related Questions