JSON Feeds For Fun and Profit Part 3- wherein Eval() kind of bums me out

(and several months later I finish my little JSON series…)

So far my exploration of JSON has been a fun-filled walk in the park. Moonbeams and rainbows. All that.

This last post on the subject is slightly less cool as I get into one of the least attractive components of the whole JSON thing- the use of eval() to transform a text response into a proper JavaScript object. The use of eval() is one of the reasons I originally was a little shy about using JSON. Why? eval() is slow and I try to stay away from slow if at all possible. That and the idea of eval()-ing code from some third party makes me wary.

Obviously, if you’re using a callback, or are just using a built in object reference which inserts itself into memory as soon as the script is attached a script to a page, eval() won’t come up, but sometimes there’s no other option but to ingest the JSON feed as plain text and eval() it into Object-hood. The feed I was helping out a co-worker with last week (AKA back in August when I originally wrote this) which spurred on this very series of posts was one such feed. It looked something like this example cribbed from JSON.org:

{
    "glossary": {
        "title": "example glossary",
		"GlossDiv": {
            "title": "S",
			"GlossList": {
                "GlossEntry": {
                    "ID": "SGML",
					"SortAs": "SGML",
					"GlossTerm": "Standard Generalized Markup Language",
					"Acronym": "SGML",
					"Abbrev": "ISO 8879:1986",
					"GlossDef": {
                        "para": "A meta-markup language, used to create markup languages such as DocBook.",
						"GlossSeeAlso": ["GML", "XML"]
                    },
					"GlossSee": "markup"
                }
            }
        }
    }
}

As you can see, if you attach that script to the document using a script tag, there’s absolutely no way to get anything out of it. No amount of poking at it will communicate the contents of that file to the rest of the scripts on the page. There’s no reference in memory and there’s no way to create one. It has to be ingested using an XMLHttpRequest and eval() has to bring it into life. Since it uses XHR and not a dynamic script tag, that means a local pass-though script on the server side is needed to get around cross site scripting constraints. In other words, we’re looking at a big pile of “why bother?” For my money, if you have to go through these steps, then plain old XML makes more sense.

Anyway, if you have to use JSON and the only option is a response structured like the above, then the following is one way to handle it.

First, an example “tag cloud” hacked together with a raw JSON tag feed from del.icio.us:

Now some code:

<script type="text/javascript">
function ajaj(json_doc,callback) {
//ajaJ? get it? so clever.
//create a cross browser XMLHttpRequest object
//let's do this
http= new function() {
var xmlhttp;
try {
//start with the standard
xmlhttp = new XMLHttpRequest();
}
catch(e)
{
//do the IE thing if the above fails
//IE deserves some props since they actually created
//the whole XMLHttp thing
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
return xmlhttp;
};
//is it okay to try this?
if1
{
//I do this in a try/catch since there's
//always a chance of some
//sort of data error and I want the
//possibility of using a fallback function
//if there is some sort of internet hiccup.
//I also hate showing errors to the user
//In this case I could just drop it since
//I'm not doing anything special here, but
//I'm not about to reinvent the wheel
//since this is more about JSON
//than the way I use XMLHttpRequest
try
{
//open the connection
http.open("GET", json_doc, true);
//set up a function to handle the response
http.onreadystatechange = function handle_http_response()
{
//I take no chances.
//you can have have readyState of 4, a status
//of 200 and still run into trouble
//I want to know all my ducks are in a row :)
//I'm all belt and suspenders
if2
{
//First I create an empty object, the same structure as the regular Delicious JSON feed
//I like the structure of their feeds so I'm replicating them here.
Delicious = {} //Use eval to bring the response into the Object
//Again, I'm using Delicious' own Delicious.tags structure
Delicious.tags=eval('('+http.responseText+')');
//we've got this handy object now that we've done our eval
//we pass it as an argument to the callback function
callback(Delicious);
}
}
}
catch(e)
{
//we could do some stuff here to handle errors
}
//let's put an end to this transaction
http.send(null);
}
}
//this is the callback function
function delicious_me(Delicious) {
//this is an object functioning as
//an associative array
//not a proper indexed array typical of most JavaScript
//so we use a for... in loop
//which loops through all the members of the array by named reference
for (var i in Delicious.tags) {
//inside the loop i will refer to the property name
//tags[i] will return the value
//BTW, the tag cloud is a total hack.
//I should do some better math here,
//but like the XHR stuff above
//this isn't really about a tag cloud...
document.getElementById("delicious").innerHTML+="<a href='http://del.icio.us/rob_react/"+i+"' style='font-size:"+Delicious.tags[i]/2+"px;line-height:"+Delicious.tags[i]/2+"px;'>"+i+"</a>\n";
}
}

The interesting bit, at least in the scope of this article, is this where we use the eval method to pull the responseText into the Delicious and pass it to the callback function.

Delicious.tags=eval('('+http.responseText+')');
callback(Delicious);

Nothing groundbreaking there and, honestly, not much for me to get excited about. I just don’t like the use of eval and would go to great lengths to avoid using it. That said, if you’re in a situation where a raw JSON feed is all you’ve got to work with, this is a way out of the jam.

For my next, and final entry in this I’ll use this handy JSON parser for the safe alternative to eval(). That should make me a little happier than this example.


  1. http.readyState==0)||(http.readyState==4 

  2. http.readyState == 4)&&(http.status==200)&&(http.responseText!=null 

Leave a Reply

Your email address will not be published. Required fields are marked *