Search code examples
javascriptjsonwhitelist

JSON.stringify whitelisting with nested objects


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.


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