Search code examples
javascripttypescriptrecursiontsx

Nested json object into certain format in typescript


I am working on it on react app with typescript. I have a complex nested Json object that should be formatted into certain format.

const a = {
    "aaa": {
        "aa": {
            "xxx": {
                "xxxx": {}
            }
        },
        "ab": {
            "xxx": {},
            "xxxx": {
                "xxxx": {}
            },
            "yyy": {
                "yyyy": {},
                "zzzz": {},
                "kkkk": {}
            }
        }
    },
    "bbb": {
        "": {}
    }
}

To do it, I made the code below.

function showJson(obj: any, label: number) {
        let returnValue = '';
        if (label === 0)
            returnValue += '['
        for (let key in obj) {
            if (typeof obj[key] === 'object') {
                returnValue += '{"value":' + label + ',';
                returnValue += '"label":"' + key + '",';
                returnValue += '"child":[' + showJson(obj[key], label + 1) + '],';
            } else {
                returnValue += '"value":' + label + ',"label":' + key + '"child":{' + obj[key] + '}}]';
            }
        }
        return returnValue;
    }

then I will parse this through Json.parse(). However, this doesn't well formatting the data.. I can't close curly braces properly and it complains 'key is duplicated.' Would anybody could help me fix it?

[
  {
    "value": "aaa",
    "label": "aaa",
    "children": [
      {
        "value": "aa",
        "label": "aa",
        "children": [
          {
            "value": "xxx",
            "label": "xxx",
            "children": [
              {
                "value": "xxxx",
                "label": "xxxx"
              }
            ]
          }
        ]
      },
      {
        "value": "ab",
        "label": "ab",
        "children": [
          {
            "value": "xxx",
            "label": "xxx"
          },
          {
            "value": "xxxx",
            "label": "xxxx",
            "children": [
              {
                "value": "xxxx",
                "label": "xxxx"
              }
            ]
          },
          {
            "value": "yyy",
            "label": "yyy",
            "children": [
              {
                "value": "yyyy",
                "label": "yyyy"
              },
              {
                "value": "zzzz",
                "label": "zzzz"
              },
              {
                "value": "kkkk",
                "label": "kkkk"
              }
            ]
          }
        ]
      }
    ]
  },
  {
    "value": "bbb",
    "label": "bbb",
    "children": [
      {
        "value": "",
        "label": ""
      }
    ]
  }
]

Solution

  • It should not be necessary to build JSON by string manipulation. Moreover, as you seem interested in the actual data structure -- since you want to call JSON.parse() on it -- there shouldn't be any need of JSON. Instead focus on building the data structure directly.

    Here is how it could be done:

    function transform(data) {
        return Object.entries(data).map(([label, data]) => {
            const children = transform(data);
            return { value: label, label, ...children.length && {children} }
        });
    }
    
    // Example from the question
    const a = {"aaa": {"aa": {"xxx": {"xxxx": {}}},"ab": {"xxx": {},"xxxx": {"xxxx": {}},"yyy": {"yyyy": {},"zzzz": {},"kkkk": {}}}},"bbb": {"": {}}}
    
    console.log(transform(a));

    If ever you would need the JSON equivalent of that resulting data structure, then call JSON.stringify on it.