agapetos agapetos - 3 months ago 66
JSON Question

Parsing nested JSON objects with duplicate keys (PHP or JS)

I am building an app that is based on a data that I am getting from an API formated as response simmilar to that of json_encode() function. Now, I don't know how (I know it is possible), that API from time to time returns duplicate keys. Since it is not my site to fix the duplicate keys, I have to find a solution how to parse this response into usable array that contains all the data sent to me.
I would like to rename duplicate keys by prepending "x01", "x02", "x03"...into their keys.
So far, I have found one solution that could help (here ), but it seams to me that it is only for the simpler arrays - I deal with nested arrays.
So, here is a demo API response:

{"boss":"mike",
"employees":{
"Josh":{
"active":"1",
"hours":"12",
"name":"Josh"},
"Josh":{
"active":"1",
"hours":"3",
"name":"Josh"}
}
}


So, as you can see, almost entire "Josh" key is duplicated (except for the "hours" sub key). Even though it looks like an error, both values are important for me.
So, this is the array that I would like to get:

array (
"boss" => "mike",
"employees" = array (
"x01Josh" = array ("active" => "1", "hours" => "12", "name" => "Josh")
"x02Josh" = array ("active" => "1", "hours" => "3", "name" => "Josh")
)
)


I've had an idea about even going one word at a time checking if it is a string, double quotes, comma or any of the curly braces and build a function accordingly. I recon it would take a very long and inefficient code (slow to process).

Since I am new to the RegEx, and since I did not find the solution with that as well (I am sure it exists, but I did not manage to find it), I am asking you for help.

I plan to parse it either in JavaScript/jQuery or PHP(using another JSON request).
Thanks in advance.

UPDATE I've forgot to mention - the reason why I'm doing this is because the second key overwrites the first one (duplicate). Also, I can't change the API (it's not my site's API). I've already asked them to implement some changes regarding those issues, but in the meantime, I have to do it from my side.

Answer

The JS solution using String.replace, String.match, Array.filter and Array.shift functions:

var jsonData = '{"boss":"mike","employees":{"Josh":{"active":"1","hours":"12","name":"Josh"},"Josh":{"active":"1","hours":"3","name":"Josh"}}}',
    re = /\"(\w+?)(?=\":\{)/g, names = {}, dups;

jsonData.match(re).forEach(function(v){
    v = v.replace(/\"/, "");
    (!names[v])? names[v] = 1 : names[v]++;
});

dups = Object.keys(names).filter(function(k) { return names[k] > 1; }); // getting duplicated keys
dups.forEach(function (k) {
    var count = names[k], i;
    names[k] = [];

    for (i = 0; i < count; i++) {
        names[k].push("x0" + (i+1));
    }
});

jsonData = jsonData.replace(re, function (p1) { // replacing duplicate keys
    p1 = p1.substr(1);
    if (dups.indexOf(p1) !== -1) {
        return '"' + names[p1].shift() + p1;
    } else {
        return '"' + p1;
    }
});

console.log(JSON.parse(jsonData));

Comments