Question

Given following example:

var test = {
    "company_name": "Foobar",
    "example": "HelloWorld",
    "address": {
        "street": "My Street 12",
        "example": "BarFoo",
        "details": "Berlin",
    }
}

console.log(JSON.stringify(test, ['company_name','address','street','example']));

// What I actually want
// console.log(JSON.stringify(test, ['company_name','address.street','address.example']));

How can I use JSON's stringify function to deal with nested objects properly?

Since I have huge JSON objects it happens that a key of a nested object is identical to it's "parent" object. I would like to specify my whitelist more granulary.

Was it helpful?

Solution

If you're willing to go to the effort of whitelisting, then you can establish an array of valid keys, which can provide the ability to nest similar to how many systems do JSON nesting (a . separator, or any separator of your choosing).

var whitelistedObj = whitelistJson(obj, ["company_name", "example", "address.street", "address.example"]);

function whitelistJson(obj, whitelist, separator) {
    var object = {};

    for (var i = 0, length = whitelist.length; i < length; ++i) {
        var k = 0,
            names = whitelist[i].split(separator || '.'),
            value = obj,
            name,
            count = names.length - 1,
            ref = object,
            exists = true;

        // fill in any empty objects from first name to end without
        //  picking up neighboring fields
        while (k < count) { // walks to n - 1
            name = names[k++];
            value = value[name];

            if (typeof value !== 'undefined') {
                if (typeof object[name] === 'undefined') {
                    ref[name] = {};
                }

                ref = ref[name];
            }
            else {
                exists = false;
                break;
            }
        }

        if (exists) {
            ref[names[count]] = value[names[count]];
        }
    }

    return object;
}

I have a JSFiddle showing its usage as well (to ensure it actually worked on my admittedly small sample set).

OTHER TIPS

You can add toJSON method in your huge JSON objects:

var test = {
    "company_name": "Foobar",
    "example": "HelloWorld",
    "address": {
        "street": "My Street 12",
        "example": "BarFoo",
        "details": "Berlin",
    },
    toJSON: function () {
        return {
            company_name: this.company_name,
            address: {
                street: this.address.street,
                example: this.address.example
            }
        }
    }
}

And, you get:

console.log(JSON.stringify(test)); // "{"company_name":"Foobar","address":{"street":"My Street 12","example":"BarFoo"}}"

Or, you can use some filter function: (this function using lodash)

function filter(object, keys, sep) {
    sep = sep || '.';
    var result = {};
    _.each(keys, function (key) {
        var keyParts = key.split(sep),
            res = object, 
            branch = {},
            branchPart = branch;

        for (var i = 0; i < keyParts.length; i++) {
            key = keyParts[i];
            if (!_.has(res, key)) {
                return;
            }

            branchPart[key] = _.isObject(res[key]) ? {} : res[key];

            branchPart = branchPart[key];
            res = res[key];
        }

        _.merge(result, branch);
    });
    return result;    
}
console.log(JSON.stringify(filter(test, ['company_name', 'address.street', 'address.example']))); // "{"company_name":"Foobar","address":{"street":"My Street 12","example":"BarFoo"}}"

Check out jsfiddle http://jsfiddle.net/SaKhG/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top