0

I have to remove blank elements of a JSON document of unknown depth. Like this one:

{
    "a": {
        "a1": ""
    },
    "b": {
        "b1": "",
        "b2": {
            "b21": "",
            "b22": {
                "b22z": "",
                "b22x": ""
            },
            "b23": ""
        },
        "b3": ""
    },
    "c": "only non-empty field"
}

I thought that the best idea was using JSON.parse to get the object and then work on it, so I got something like this:

enter image description here
I found this function in this post, but it isn't working as I expeceted:

function filter(obj) {
    $.each(obj, function(key, value){
        if (value === "" || value === null){
            delete obj[key];
        } else if (Object.prototype.toString.call(value) === '[object Object]') {
            filter(value);
        } else if ($.isArray(value)) {
            $.each(value, function (k,v) { filter(v); });
        }
    });
}

After calling that function with my object, I get an object with empty properties, which I don't want to show up:

enter image description here

How could I modify the code above to get this? I've tried everything I know and I'm going mad...
Thanks

rmdez
  • 41
  • 7
  • 1
    What if b2 would have a value would you like to keep the nesting? or would you just like to flatten the whole? The problem with your current solution is that the function evaluates your JSON object recursively. You could let the filter function return the number of items in the current level, if it is 0, also remove the current object – Gijs Beijer Apr 21 '20 at 11:47
  • If b2 had a value, there wouldn't be nesting beyond that point. I mean, if I had 'b2':'hello', I wouldn't have elements like b21, but could have b3 for example.I think the solution you're thinking could work, but I don't really know how to keep the count of items in a level. – rmdez Apr 21 '20 at 12:01
  • Does this answer your question? [recursively remove undefined from object (including parent)](https://stackoverflow.com/questions/43781215/recursively-remove-undefined-from-object-including-parent) – Kid Apr 21 '20 at 12:04
  • Did any of these answers help you? If so you should either accept one or, let them know how you fixed it in the end. – Gijs Beijer Apr 22 '20 at 06:53
  • @GijsBeijer yes, sorry for the waiting, I've been busy. Your solution is the more adecuate, it works quite good. Nevertheless, there's still something not working, but I haven't had the time to debug. Later today I'll be able to tell you! – rmdez Apr 22 '20 at 07:48
  • Great, good luck, if you let me know what the fault in my script was I'll update the answer – Gijs Beijer Apr 22 '20 at 07:54

2 Answers2

1

Code in a comment won't work so I'll type it here again:

function removeEmptyEntries(object) {
    let allEmpty = true;

    for (let item in object) {

        if (typeof object[item] == "object") {
            if(removeEmptyEntries(object[item]))
            {
                delete object[item];
            } else {
                allEmpty = false;
            }

        } else if (object[item]=="") {
            delete object[item]
        } else {
            allEmpty = false;
        }
    }

    return allEmpty;
}

warning: did this from the top of my head, so its untested.

Gijs Beijer
  • 560
  • 5
  • 19
  • After debugging your code, I found the problem I told you. Imagine an object like this: {'b': {'b1': 'whatever', 'b2': ''}}. When calling your function with this object, it should return {'b': {'b1': 'whatever'}}. However, it returns an empty object. This is because the last call (i.e (removeEmptyEntries(b2) ) returns true. The behaviour of this is that b2 is deleted, which is correct, but doesn't change the value of allEmpty to false, so it will treat b as empty and delete it too. How would you fix this? – rmdez Apr 22 '20 at 18:14
  • Hi I edited my answer which should do the trick. I forgot to define the variable with 'let'. creating a variable without a 'let' automaticaly puts it on the global scope. – Gijs Beijer Apr 22 '20 at 20:16
  • Hi Gijs, the correction you made is correct. Even so, I had to add another condition to get the result I expected. I just had to add an else to the most inner if [if(removeEmptyEntries..){...} else{ allEmpty = false;}. Without this condition, a property can be deleted if it's not in the first level (no nesting). Just telling you in case you'd like to update your answer again. Now everything works fine, thanks for your help :-) – rmdez Apr 23 '20 at 14:45
  • Good thinking, didn't think of that! Again, did it from the top of my head :p. Good to hear you got it working, I'll put it in my answer later – Gijs Beijer Apr 23 '20 at 14:51
0

Is this the sort of thing you want?

function remove(object) {
    for (let item in object) {
        if (typeof object[item] == "object") {
            remove(object[item])
        } else {
            if (object[item]=="") {
                delete object[item]
            }
        }
    }
    return object
}

const obj = {
    "a": {
        "a1": ""
    },
    "b": {
        "b1": "",
        "b2": {
            "b21": "",
            "b22": {
                "b22z": "",
                "b22x": ""
            },
            "b23": ""
        },
        "b3": ""
    },
    "c": "only non-empty field"
}

console.log(remove(obj))
Lebster
  • 289
  • 5
  • 12
  • 1
    What's the difference between these two solutions? – Kid Apr 21 '20 at 11:58
  • @O.o one was incorrectly changed, but I have fixed now and removed the one not relevant to the question – Lebster Apr 21 '20 at 11:59
  • wouldn't this still leave the empty objects in the tree? – Gijs Beijer Apr 21 '20 at 12:54
  • `function removeEmptyEntries(object) { allEmpty = true; for (let item in object) { if (typeof object[item] == "object") { if(removeEmptyEntries(object[item])) { delete object[item]; } } else if (object[item]=="") { delete object[item] } else { allEmpty = false; } } return allEmpty; }` something like this would also remove the empty objects (warning: did this from the top of my head, so its untested) – Gijs Beijer Apr 21 '20 at 13:08
  • As @GijsBeijer said, this code from Lebster doesn't remove the empty objects from the tree. The solution he gave is more adecuate for this problem. – rmdez Apr 22 '20 at 07:46