Traverse nested object and change values - javascript

I've got an object containing user-data alongside some dates. I'd like to format these dates (as they are delivered like this 2015-02-13T18:25:37+01:00).
I'd like to have the values of the object changed in-place but how can I do this?
I traverse the object like this:
$.each(myObject, formatDates)
var isDate = function(value) {
return (value!==null && !isNaN(new Date(value)))
}
var formatDates = function(key, value){
if (isDate(value)) {
// Change value here
console.log("key:" + key + " value: " + value)
}
// Recursive into child objects
if (value !== null && typeof value === "object") {
$.each(value, formatDates)
}
}

You can use this
function iterate(obj) {
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
if (typeof obj[property] == "object") {
iterate(obj[property]);
} else {
// do your date thing
}
}
}
return obj;
}
iterate(object)

Related

Check for special characters in every JSON field [duplicate]

I have an object which has inner objects and properties defined like this:
var obj = {obj1 : { "prop1" : "nothing", "prop2" : "prop"},
obj2 : {"prop1" : "nothing", "prop2" : "prop"},
pr1 : "message",
pr2 : "mess"
};
Normally to iterate every property of an object , the for .. in loop can do the trick
for (property in obj){
if (obj.hasOwnProperty(property)){
console.log(property + " " + obj[property]);
}
}
the console displayed :
obj1 [object Object]
obj12 [object Object]
pr1 message
pr2 mess
However how to iterate the inner objects (obj1, obj2) and their own properties (prop1,prop2) ?
Recursion is your friend:
function iterate(obj) {
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
if (typeof obj[property] == "object")
iterate(obj[property]);
else
console.log(property + " " + obj[property]);
}
}
}
Note: don't forget to declare property locally using var!
That's great anwsers, although the array cases is not covered, here's my contribution:
var getProps = function (obj) {
for (var property in obj) {
if (obj.hasOwnProperty(property) && obj[property] != null) {
if (obj[property].constructor == Object) {
getProps(obj[property]);
} else if (obj[property].constructor == Array) {
for (var i = 0; i < obj[property].length; i++) {
getProps(obj[property][i]);
}
} else {
console.log(obj[property]);
}
}
}
}
getProps(myObject);
To simply display the object structure, I often use: console.log (JSON.stringify (obj))
You can use recursion to achieve that:
function Props(obj) {
function getProps(obj){
for (var property in obj) {
if (obj.hasOwnProperty(property)){
if (obj[property].constructor == Object) {
console.log('**Object -> '+property+': ');
getProps(obj[property]);
} else {
console.log(property + " " + obj[property]);
}
}
}
}
getProps(obj);
}
see http://jsfiddle.net/KooiInc/hg6dU/

Javascript - traverse tree like object and add a key

Suppose I have an object with depth-N like:
food = {
'Non-Animal': {
'Plants' : {
'Vegetables': {
...
}
},
'Minerals' : {
...
}
},
'Animal': {
...
}
}
And I want to add in this object the category 'Fruits', but I have to search the object where 'Plants' are and then add it. So I don't want to do in one statement:
food['Non-Animal']['Plants']['Fruits'] = {};
Since I want to search first where it belongs.
How can I add the fruits category to the object while iterating through it? What I have so far is:
addCategory(food, category, parent);
function addCategory(obj, category, parent_name) {
for (var key in obj) {
if (key == parent_name) {
obj[key][category] = {};
}
var p = obj[key];
if (typeof p === 'object') {
addCategory(p, category, parent);
} else {
}
}
}
How can I fix this routine to do this or is there a better way to do this?
If I'm understanding you correctly, I think you'd want your function to define a variadic parameter that takes individual names of the path you wish to traverse and create if necessary.
Using .reduce() for this makes it pretty easy.
const food = {
'Non-Animal': {
'Plants': {
'Vegetables': {}
},
'Minerals': {}
},
'Animal': {}
}
console.log(addCategory(food, "Non-Animal", "Plants", "Fruits"));
console.log(addCategory(food, "Non-Animal", "Minerals", "Gold"));
function addCategory(obj, ...path) {
return path.reduce((curr, name) => {
if (!curr) return null;
if (!curr[name]) return (curr[name] = {});
return curr[name];
// More terse but perhaps less readable
// return curr ? curr[name] ? curr[name] : (curr[name]={}) : null;
}, obj);
}
console.log(JSON.stringify(food, null, 2));
Looks fine. However you might want to terminate after adding the prop:
function addCategory(obj, category, parent_name) {
for (var key in obj) {
if (key == parent_name){
return obj[key][category] = {};
}
var p = obj[key];
if (typeof p === 'object') {
if(addCategory(p, category, parent)) return true;
}
}
}
I see only one mistake: The recursive call of addCategory cannot find the parent-variable, cause it's called parent_name in your scope.
var food = {
'Non-Animal': {
'Plants' : {
'Vegetables': {
}
},
'Minerals' : {}
},
'Animal': {}
}
function addCategory(obj, category, parent_name) {
for (var key in obj) {
if (key == parent_name){
obj[key][category] = {};
}
var p = obj[key];
if (typeof p === 'object') {
addCategory(p, category, parent_name);
} else {
}
}
}
console.log(food);
addCategory(food, 'Fruits', 'Plants');
console.log(food);
You can use reduce to create function that will take key as string and object as value that you want to assign to some nested object.
var food = {"Non-Animal":{"Plants":{"Vegetables":{}},"Minerals":{}},"Animal":{}}
function add(key, value, object) {
key.split('.').reduce(function(r, e, i, arr) {
if(r[e] && i == arr.length - 1) Object.assign(r[e], value);
return r[e]
}, object)
}
add('Non-Animal.Plants', {'Fruits': {}}, food)
console.log(food)

show nested json data in treeview in javascript

i have nested json data. i used the blow function.
var jsonSource={"error_code":0, "ext_info":{"name":{"firstName":"John","lastName":"Jonson","nickName":"JJ"}}};
var obj=JSON.parse(jsonSource),returnValue;
function showJson(obj){
for(var key in obj){
if(typeof obj[key]==='object'){
returnValue+='<div>'+key+'/\n';
showJson(obj[key]);
returnValue+='</div>';
} else{
returnValue+=key+'equal'+obj[key];
}
}
docoument.getElementById('data').innerHTML=returnValue;
}
as i said before , i have a large nested json data and when i parse it to showJson function ,it just shows one level of json data and puts others deep level of dataJson undefined.
what should i do to resolve the problem?
Recursive approach works more intuitively when done with actual return values. Have a look at https://jsfiddle.net/ughnjfh0/1/
var jsonSource='{"error_code":0, "ext_info":{"name":{"firstName":"John","lastName":"Jonson","nickName":"JJ"}}}';
var obj=JSON.parse(jsonSource);
function showJson(obj){
var returnValue='';
for(var key in obj){
if(typeof obj[key]==='object'){
returnValue+='<div>'+key+'/\n';
returnValue+=showJson(obj[key]);
returnValue+='</div>';
} else{
returnValue+=key+'equal'+obj[key];
}
}
return returnValue;
}
document.getElementById('data').innerHTML= showJson(obj);
Also:
jsonSource should be a string to be properly parsable as JSON data
typo in docoument.getElementById('data').innerHTML=returnValue;
Some of your problems:
jsonSource is already an object
you try to assign the returnValue in every call of showJson
Better to use a clean approach for looping and returning of the items:
var obj = { "error_code": 0, "ext_info": { "name": { "firstName": "John", "lastName": "Jonson", "nickName": "JJ" } } };
function showObj(obj) {
return Object.keys(obj).map(function (k) {
if (typeof obj[k] === 'object') {
return k + ':<br><div style="margin-left: 25px;">' + showObj(obj[k]) + '</div>';
}
return k + ': ' + obj[k];
}).join('<br>');
}
document.getElementById('data').innerHTML = showObj(obj);
<div id="data"></div>
// obj is the object to loop, ul is the ul to append lis to
function loop(obj, ul) {
$.each(obj, function(key, val) {
if(val && typeof val === "object") { // object, call recursively
var ul2 = $("<ul>").appendTo(
$("<li>").appendTo(ul)
);
loop(val, ul2);
} else {
$("<li>").text(val).appendTo(ul);
}
});
}
var ul = $("<ul>");
var jsonSource={"error_code":0, "ext_info":{"name":{"firstName":"John","lastName":"Jonson","nickName":"JJ"}}};
var data=JSON.parse(jsonSource)
loop(data, ul);
ul.addClass("my-new-list").appendTo('body');

Is there a javascript serializer for JSON.Net?

I am using Newtonsoft JSON.Net to deserialize an object with PreserveReferencesHandling enabled. jQuery does not support relinking references based on the $ref and $id syntax JSON.Net uses (I don't know if jQuery supports this functionality in any capacity).
I tried using Douglas Crockford's cycle.js but that does not seem to work with my objects, the returned object is identical to the object which got passed in.
I am not incredibly familiar with JSON.Net, but I cannot seem to find any javascript libraries which would serialize (or parse) the JSON their .NET component outputs.
How can I accomplish putting back together object references?
I was looking for a solution to this problem as well, and ended up hacking Douglas Crockford's JSON.retrocycle function. His function does not work for the $ref=some number, but it looks for something like an xpath.
This is my quick and dirty version - don't use this as is - I'm not doing any cleanup, and it probably should be a plugin, but it does the job and is good enough to get going:
function retrocycle(o) {
var self = this;
self.identifiers = [];
self.refs = [];
self.rez = function (value) {
// The rez function walks recursively through the object looking for $ref
// properties. When it finds one that has a value that is a path, then it
// replaces the $ref object with a reference to the value that is found by
// the path.
var i, item, name, path;
if (value && typeof value === 'object') {
if (Object.prototype.toString.apply(value) === '[object Array]') {
for (i = 0; i < value.length; i += 1) {
item = value[i];
if (item && typeof item === 'object') {
path = item.$ref;
if (typeof path === 'string' && path != null) {
//self.refs[parseInt(path)] = {};
value[i] = self.identifiers[parseInt(path)]
} else {
self.identifiers[parseInt(item.$id)] = item;
self.rez(item);
}
}
}
} else {
for (name in value) {
if (typeof value[name] === 'object') {
item = value[name];
if (item) {
path = item.$ref;
if (typeof path === 'string' && path != null) {
//self.refs[parseInt(path)] = {};
value[name] = self.identifiers[parseInt(path)]
} else {
self.identifiers[parseInt(item.$id)] = item;
self.rez(item);
}
}
}
}
}
}
};
self.rez(o);
self.identifiers = [];
}
Use it like this:
$.post("url/function", { ID: params.ID }, function (data) {
retrocycle(data)
// data references should be fixed up now
}, "json");
You would have to write in a double look-up into your js parser. Technically preserving reference handling is to get around circular references, which is to say what would normally cause a stack overflow during parsing.
JSON does not have a native syntax for handling this. Newtonsoft version is a custom implementation, thus parsing the JSON will be a custom implementation.
If you really have to preserve such references, XML may be a better solution. There are some json->xml libraries out there.
Here is one solution for parsing that may be of use, or at least a guide:
https://blogs.oracle.com/sundararajan/entry/a_convention_for_circular_reference
This is my enhanced version of #Dimitri. #Dimitri code sometimes isn't able to rebuild the references. If anyone improves the code, please, tell me.
Regards,
Marco Alves.
if (typeof JSON.retrocycle !== 'function') {
JSON.retrocycle = function retrocycle(o) {
//debugger;
var self = this;
self.identifiers = [];
self.refs = [];
self.buildIdentifiers = function (value) {
//debugger;
if (!value || typeof value !== 'object') {
return;
}
var item;
if (Object.prototype.toString.apply(value) === '[object Array]') {
for (var i = 0; i < value.length; i += 1) {
item = value[i];
if (!item || !item.$id || isNaN(item.$id)) {
if (item) {
self.buildIdentifiers(item);
}
continue;
}
self.identifiers[parseInt(item.$id)] = item;
self.buildIdentifiers(item);
}
return;
}
for (var name in value) {
if (typeof value[name] !== 'object') {
continue;
}
item = value[name];
if (!item || !item.$id || isNaN(item.$id)) {
if (item) {
self.buildIdentifiers(item);
}
continue;
}
self.identifiers[parseInt(item.$id)] = item;
self.buildIdentifiers(item);
}
};
self.rez = function (value) {
// The rez function walks recursively through the object looking for $ref
// properties. When it finds one that has a value that is a path, then it
// replaces the $ref object with a reference to the value that is found by
// the path.
var i, item, name, path;
if (value && typeof value === 'object') {
if (Object.prototype.toString.apply(value) === '[object Array]') {
for (i = 0; i < value.length; i += 1) {
item = value[i];
if (item && typeof item === 'object') {
if (item.$ref)
path = item.$ref;
if (typeof path === 'string' && path != null) {
//self.refs[parseInt(path)] = {};
value[i] = self.identifiers[parseInt(path)];
continue;
}
//self.identifiers[parseInt(item.$id)] = item;
self.rez(item);
}
}
} else {
for (name in value) {
if (typeof value[name] === 'object') {
item = value[name];
if (item) {
path = item.$ref;
if (typeof path === 'string' && path != null) {
//self.refs[parseInt(path)] = {};
value[name] = self.identifiers[parseInt(path)];
continue;
}
//self.identifiers[parseInt(item.$id)] = item;
self.rez(item);
}
}
}
}
}
};
self.buildIdentifiers(o);
self.rez(o);
self.identifiers = []; // Clears the array
};
}

Using a JSON.parse reviver to obfuscate fields

I am attempting to abuse a reviver function with JSON.parse.
I basically want to make certain fields "null".
If I do this:
var json_data = JSON.parse(j, function(key, value) {
if (key == "name") {
return value;
} else {
return null;
}
});
The entire json_data object ends up null. In fact, no matter what I make the else, that defines the value of the json_object.
Interestingly, this works as expected:
var json_data = JSON.parse(j, function(key, value) {
if (key == "name") {
return "name";
} else {
return value;
}
});
The property "name" now has a value of "name".
JSON in question:
var j = '{"uuid":"62cfb2ec-9e43-11e1-abf2-70cd60fffe0e","count":1,"name":"Marvin","date":"2012-05-13T14:06:45+10:00"}';
Update
I just realized that the inverse of what I want to do works as well so I can nullify the name field:
var json_data = JSON.parse(j, function(key, value) {
if (key == "name") {
return null;
} else {
return value;
}
});
Through some experimentation, it looks like a final call is made to the function where the key is an empty string and the value is the top-level object:
> JSON.parse('{"hello": "world"}', function(k, v) { console.log(arguments); return v; })
["hello", "world"]
["", Object]
So you could use:
var json_data = JSON.parse(j, function(key, value) {
if (key == "name" || key === "") {
return value;
} else {
return null;
}
});
Now, since "" does appear to be a valid JSON key, to be 100% correct it might be better to use something like:
var json_data;
JSON.parse(j, function(key, value) {
if (key == "name") {
return value;
} else if (key === "") {
json_data = value;
return null;
} else {
return null;
}
});
But that might be a little bit paranoid ;)
It has a rather interesting behavior that the entire object is included in the objects passed to the reviver.
When the entire object is passed, the key is null.
http://jsfiddle.net/sGYGM/7/
var j = '{"uuid":"62cfb2ec-9e43-11e1-abf2-70cd60fffe0e","count":1,"name":"Marvin","date":"2012-05-13T14:06:45+10:00"}';
var json_data = JSON.parse(j, function(k, v) {
if (k === "" || k == "name") {
return v;
} else {
return null;
}
});
console.log(json_data);
As per https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/JSON/parse
The reviver is ultimately called with the empty string and the topmost value to permit transformation of the topmost value. Be certain to handle this case properly, usually by returning the provided value, or JSON.parse will return undefined.

Categories

Resources