Reputation: 13
I have a JSON object that I use as a theme (It's for Appcelerator, but really, it doesn't matter since this is more of a JSON question.) I do have have access to underscore.js if that helps with traversals/functions...but pure JS would work as well.
I need to traverse the JSON tree and move a child objects properties to it's parents if that key is a certain value, but also omit that object if it it's key another value. This needs to happen at multiple levels of the JSON tree. So I need some sort of recursive function.
For an example, let's say I need to move all properties of a child object with a key of ANDROID
to it's parent object, but ignore the object and properties if a key is IOS
:
Original Object
var theme = {
Form: {
LabelTop: {
backgroundColor: 'red',
fieldBorderColor: '#cacacf',
rowHeight: 40,
hintText: {
font: {
fontSize: 12
},
colorOn: '#3accf1',
colorOff: '#cacacf',
ANDROID: {
width: 200
}
},
}
},
Modal: {
id: 'md',
backgroundColor: '#fff',
IOS: {
color: 'red'
}
}
};
I'd like to be able to call something like this:
var newTheme = parsePlatform(theme, 'ANDROID', 'IOS');
Where theme
is the object to search, ANDROID
is the key to merge and IOS
is the key to skip
With this example I'm moving/replacing all properties of a parent object with the child properties if the key is ANDROID
, but I'm not including any with a parent key of IOS
. In this example I would expect the output to be this:
Modified Object
var theme = {
Form: {
LabelTop: {
backgroundColor: '#fff', // replaced
fieldBorderColor: '#cacacf',
rowHeight: 40,
hintText: {
font: {
fontSize: 12
},
colorOn: '#3accf1',
colorOff: '#cacacf',
width: 200 // 'ANDROID' prop moved
}
}
},
Modal: {
// IOS removed
id: 'md',
backgroundColor: '#fff'
}
};
Notice Modal
doesn't have a color
property because i'm only looking for ANDROID
, not IOS
I've been able to get the results i'm looking for if I know the JSON depth and hard code it in. Once I move to a recursive function everything blow up. Any help would be appreciated.
Upvotes: 1
Views: 2523
Reputation: 16615
Normally I would ask what you have tried, but this question was interesting to me, the following is not heavily tested, but seems to do the job:
function mergeExtend(obj, merge, skip) {
var o, o1, nObj = {};
for (o in obj) {
// ensure we are only checking this obj's keys
if (obj.hasOwnProperty(o)) {
// check if we have keys to merge
if ((merge || []).indexOf(o) > -1) {
// if something was defined in merge, we expect the value to be an object
for (var o1 in obj[o]) {
if (obj[o].hasOwnProperty(o1)) {
// put child obj val under parent key
nObj[o1] = obj[o][o1];
}
}
// ensure we are not skipping this key
} else if ((skip || []).indexOf(o) === -1) {
if (typeof obj[o] === 'object') {
// go recursive if we are not merging and val is an object
nObj[o] = mergeExtend(obj[o], merge, skip);
} else {
// otherwise just copy the key val over
nObj[o] = obj[o];
}
}
}
}
return nObj;
}
console.log(mergeExtend(theme, ['ANDROID'], ['IOS']));
And the FIDDLE
Upvotes: 1