How do I know if a variable is JSON or if it is something else? Is there a JQuery function or something I can use to figure this out?
JSON is an encoding method not an internal variable type.
You might load in some text that is JSON encoded that javascript then uses to populate your variables. Or you might export a string that contains a JSON encoded dataset.
Here's a function I got from who-knows-where a while ago. It's synonymous with it's Prototype isJson()
counterpart:
jQuery.isJson = function(str) {
if (jQuery.trim(str) == '') return false;
str = str.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
}
Put that somewhere, and then simply call $.isJson(not_sure_if_this_is_json);
The only testing I've done is to check for a string, with and without double quotes, and this passes that test. http://forum.jquery.com/topic/isjson-str
Edit: It looks like the latest Prototype has a new implementation similar to the one linked above. http://prototypejs.org/assets/2010/10/12/prototype.js
function isJSON() {
var str = this;
if (str.blank()) return false;
str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@');
str = str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
str = str.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
return (/^[\],:{}\s]*$/).test(str);
}
Based on your comments, it sounds like you don't want to know whether a string is valid JSON, but rather whether an object could be successfully encoded as JSON (e.g. doesn't contain any Date objects, instances of user-defined classes, etc.).
There are two approaches here: try to analyze the object and its "children" (watch out for recursive objects) or suck-it-and-see. If you have a JSON encoder on hand (JSON.stringify
in recent browsers or a plugin such as jquery-json), the latter is probably the simpler and more robust approach:
function canJSON(value) {
try {
JSON.stringify(value);
return true;
} catch (ex) {
return false;
}
}
Analyzing an object directly requires that you be able to tell whether it is a "plain" object (i.e. created using an object literal or new Object()
), which in turn requires you be able to get its prototype, which isn't always straightforward. I've found the following code to work in IE7, FF3, Opera 10, Safari 4, and Chrome (and quite likely other versions of those browsers, which I simply haven't tested).
var getPrototypeOf;
if (Object.getPrototypeOf) {
getPrototypeOf = Object.getPrototypeOf;
} else if (typeof ({}).__proto__ === "object") {
getPrototypeOf = function(object) {
return object.__proto__;
}
} else {
getPrototypeOf = function(object) {
var constructor = object.constructor;
if (Object.prototype.hasOwnProperty.call(object, "constructor")) {
var oldConstructor = constructor; // save modified value
if (!(delete object.constructor)) { // attempt to "unmask" real constructor
return null; // no mask
}
constructor = object.constructor; // obtain reference to real constructor
object.constructor = oldConstructor; // restore modified value
}
return constructor ? constructor.prototype : null;
}
}
// jQuery.isPlainObject() returns false in IE for (new Object())
function isPlainObject(value) {
if (typeof value !== "object" || value === null) {
return false;
}
var proto = getPrototypeOf(value);
// the prototype of simple objects is an object whose prototype is null
return proto !== null && getPrototypeOf(proto) === null;
}
var serializablePrimitives = { "boolean" : true, "number" : true, "string" : true }
function isSerializable(value) {
if (serializablePrimitives[typeof value] || value === null) {
return true;
}
if (value instanceof Array) {
var length = value.length;
for (var i = 0; i < length; i++) {
if (!isSerializable(value[i])) {
return false;
}
}
return true;
}
if (isPlainObject(value)) {
for (var key in value) {
if (!isSerializable(value[key])) {
return false;
}
}
return true;
}
return false;
}
So yeah… I'd recommend the try/catch approach. ;-)