最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Turn javascript dictionary into JSON format - Stack Overflow

programmeradmin2浏览0评论

I have a javascript dictionary:

{
  "a": {
      "b": {
          "c": null,
          "d": null
           }
       }
}

How can I turn it into a JSON object which I can specify the name and children property? Is there any elegant way to do it? The JSON object could be:

{
    name:"a"
    children: [{
      name:"b",
      children: [{
          name:"c",
          children: null
           },{
          name:"d",
          children: null}]
       }]
  }

I have a javascript dictionary:

{
  "a": {
      "b": {
          "c": null,
          "d": null
           }
       }
}

How can I turn it into a JSON object which I can specify the name and children property? Is there any elegant way to do it? The JSON object could be:

{
    name:"a"
    children: [{
      name:"b",
      children: [{
          name:"c",
          children: null
           },{
          name:"d",
          children: null}]
       }]
  }
Share Improve this question edited Mar 6, 2015 at 19:51 Gabriel asked Mar 6, 2015 at 19:00 GabrielGabriel 6111 gold badge10 silver badges26 bronze badges 4
  • You will need to write a recursive function. – dfsq Commented Mar 6, 2015 at 19:03
  • I'm not sure it was intentional, but this is the first time I've ever seen "JSON Object" written in a post that didn't make me flare up with the need to get all pedantic about JSON strings vs JavaScript objects. Bravo. – Evan Davis Commented Mar 6, 2015 at 19:09
  • That said, your "JSON Object" isn't valid JSON; the keys need to be in double quotes as well. – Evan Davis Commented Mar 6, 2015 at 19:09
  • Sorry for the confusion, change the question – Gabriel Commented Mar 6, 2015 at 19:52
Add a ment  | 

3 Answers 3

Reset to default 3

You could create a recursive function for generating your output:

var x = {
    "a": {
        "b": {
            "c": null,
            "d": null
        }
    }
};

function generate(item, key) {
    var result = {
        name: key,
        children: []
    };

    for (var _ in item)
        result.children.push(generate(item[_], _))

    if (result.children.length == 0)
        result.children = null;

    return (key == undefined) ? result.children : result;
}

console.log(JSON.stringify(generate(x), null, 1));

Output:

[
 {
  "name": "a",
  "children": [
   {
    "name": "b",
    "children": [
     {
      "name": "c",
      "children": null
     },
     {
      "name": "d",
      "children": null
     }
    ]
   }
  ]
 }
]

The above generate function returns a list instead of a dictionary, because it's possible to have more than one name at the root level. But if we are sure that we have only one name at the root name, we can generate the json like this:

console.log(JSON.stringify(generate(x)[0], null, 1));

Here's my solution. It's similar to JuniorCompressor's.

function generate(obj) {
  // Return primitives as-is
  if (!(obj instanceof Object)) return obj;

  // Loop through object properties and generate array
  var result = [];
  for (var key in obj) {
    result.push({
      name:     key,
      children: generate(obj[key])
    });
  }

  // Return resulting array
  return result;
}

As mentioned, the resulting object will actually be an array (in case there is more than one root-level property in the original object). If you really need the resulting object to be an object with only properties name and value, then you should access the first element of the resulting array, like this:

generate(obj)[0]

Solution

You need a recursive function, which calls itself for children. Note that in your example, there is only one top-level child (a). I instead use the assumption that the top-level 'name' refers to the name of the actual object itself. If you want to get results exactly like you demonstrate, from an object called 'obj', run toJSON(obj).children[0]. For the overall function, try something like the following:

function toJSON(obj, name) {
    var subTree = {
        name: name,
        children: []
    };
    if (obj !== null && Object.keys(obj).length >= 1) {
        for (var child in obj) {
            subTree.children.push(toJSON(obj[child], child));
        }
    } else {
        subTree.children = null;
    }
    return subTree;
}

Results of toJSON(obj).children[0]:

{
    "name": "a",
    "children": [{
        "name": "b",
        "children": [{
            "name": "c",
            "children": null
        },{
            "name": "d",
            "children": null
        }]
    }]
}

Results of toJSON(obj, 'obj'):

{
    "name": "obj",
    "children": [{
        "name": "a",
        "children": [{
            "name": "b",
            "children": [{
                "name": "c",
                "children":null
            },
            {
                "name": "d",
                "children": null
            }]
        }]
    }]
}

Here's a line-by-line explanation:

  1. Declares the function, which expects two arguments: the object, and it's name. If you're going to be using toJSON(obj).children[0], though, don't bother with the second argument. It won't affect the result.
  2. Declares the result, an object containing information about the current level and all levels below in the object. If you consider the object a tree, this result contains information about the current branch, and all it's branches.
  3. Declares the property 'name', containing the name/key of the object at the current level. When you call the function, you need to include the name as second argument because there is no way of dynamically finding the name of a variable. They're passed into functions by value. As described above, though, if you're looking for results EXACTLY like those in your example, you're going to use toJSON(obj).children[0], instead of toJSON(obj, 'obj'), and then don't need to bother with the second argument.
  4. Declares the children array, to be filled below
  5. Terminates the declaration begun on Line 2
  6. Checks if the object ISN'T null, and that it has children, using a handy method of the Object built-in object, running Lines 7, 8 and 9 if so
  7. Iterates over the children of the object, running Line 8 for each child
  8. Recursively runs the toJSON() function for each child, to get it's subTree. Because the children can't dynamically figure out their own names, it passes those in as well.
  9. Terminates the for loop begun at Line 7
  10. If there are no children, run Line 11. This is only run if Lines 7, 8 and 9 are not.
  11. Sets children to null (only run if there are no children, as checked by Line 6)
  12. Terminates the else started at line 10
  13. Returns the current subTree, either to the function if called recursively by the function, or to you if you called it yourself
  14. Terminates the function

Information about the Previous Version, Pre-edit

The original function only used one argument, whereas that above has another argument for 'name'. This is because the original tried to figure out the name of each level within that same level, which I have since realized isn't possible in Javascript. Basically, the original didn't work, and an extra argument had to be added to make it work. For records' sake, though, here was the original function:

// THIS FUNCTION DOESN'T WORK. IT'S HERE ONLY FOR HISTORICAL ACCURACY:
function toJSON(obj) {
    var subTree = {
        name: obj.constructor.name,       // This should get the object key
        children: []
    };
    if (Object.keys(obj).length >= 1) {   // If there is at least one child
        for (var child in obj) {
            subTree.children.push(toJSON(obj[child]));
        }
    } else {
        subTree.children = null;
    }
    return subTree;
}
发布评论

评论列表(0)

  1. 暂无评论