views:

416

answers:

6

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?

+1  A: 

Use json2.js to parse it.

Ignacio Vazquez-Abrams
This nearly worked... If you pass var json = {"test":"test"} to it.. it wont work.. so if you do a stringify on it.. it will pass that validation, but if you pass a normal string ("asdf") to it.. it won't throw an error?!
James Armstead
I think the idea is to have it pass isJSON before sending it to json2.js's JSON.parse.
Adam
+2  A: 

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.

PP
+2  A: 

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);

David Titarenco
...interesting :)
karim79
I passed "ata" to this thing and it returned True?
James Armstead
This incorrectly returns true for strings not enclosed in double quotes.
Adam
A: 

do eval('(' + mightBeJson + ')') on it.

BrennaSoft
eval is evil - http://www.jslint.com/lint.html#evil
Adam
and eval won't really help you determine whether the string is valid JSON or not; invalid JSON can still `eval` just fine.
Andrzej Doyle
Which is, actually, part of the danger of `eval`
Ryan Kinal
A: 

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);

}

Adam
+1  A: 

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. ;-)

Ben Blank