Displaying articles with tag "jsonquery"

There are 2 articles with this tag.

May 17

When I first mentioned JSONQuery, I actually posted the core functionality of a more comprehensive parser. While I tried to keep things simple by writing queries in JavaScript, the task at the time required a tiny slice of custom syntax. Because JSONQuery grew in size, and in order to keep things simple, I stripped out the custom bits before writing up the original post. In hindsight, I realize the original code may be more complex than it needs to be.

If JSONQuery accepts queries written in JavaScript, why should we waste time with a custom parser when JavaScript has a built-in parser, namely eval? That all depends on how you feel about eval. For example, Douglas Crockford famously frowns upon eval:

The eval function (and its relatives, Function, setTimeout, and setInterval) provide access to the JavaScript compiler. This is sometimes useful for parsing JSON text, but in virtually all other cases it indicates the presences of extremely bad coding. The eval function is the most misused feature of JavaScript.

JSONQuery is at its core a JavaScript parser. Since any JSON text has presumably already been parsed and converted into an Object, what we're actually building is a general purpose Object query. So, assuming you're comfortable with eval in this context, JSONQuery evolves into Object.query and becomes even simpler. Here is the new Object.query in action:

Object.prototype.query = function(query) {
  var result = eval('this.' + query);
  return !!result ? result : null;
};

var json = {
  'name': 'Bob',
  'address': [{
      'street': '1234 Main St.',
      'city' : 'New York',
      'state': 'NY',
      'zip': '10101'
    },{
      'street': '5678 First St.',
      'city' : 'San Francisco',
      'state': 'CA',
      'zip': '94126'
    }]
};

json.query('address[1].zip'); // 94126

Of course, there are still issues present in this minimalist implementation. Are we certain query is a String? Are we certain query is safe to eval? Are there other sanitizations we should perform? What can be done about any parse errors during eval? These are basic issues that can be easily corrected before putting Object.query into the wild.

These issues aside, the evolution of JSONQuery to Object.query has several benefits. It's much easier to understand what's happening. By its nature, eval is much faster than the original parser. Finally, it's more useful as a method present on any Object. All of this assumes, of course, that there is a need to retrieve the value of a specific property of an object at any given depth dynamically, using queries generated at run-time.

Apr 03

JSONQuery

2007 at 01:24 PM

Let's assume you have a JSON object with a predictable structure. Let's also assume you need a way to retrieve the value a specific field, at any given depth, dynamically. That is, you don't know ahead of time exactly which field's value you need. The query will be generated at run time.

JSONQuery allows you to access the value of a specific field of a JSON object by applying a query string written in JavaScript syntax.

Here's a simple example of JSONQuery in action:

var json = {
  'name': 'Bob',
  'address': [
    {
      'street': '1234 Main St.',
      'city' : 'New York',
      'state': 'NY',
      'zip': '10101'
    },
    {
      'street': '5678 First St.',
      'city' : 'San Francisco',
      'state': 'CA',
      'zip': '94126'
    }
  ]
};

var query = 'address[1].zip',
    val   = jsonQuery(json, query);

console.log(val); // 94126

I realize at first glance it may seem silly to even go down this path. But the need arose recently where I needed something just like this. It may still be silly, but it works damn well. If you have suggestions or improvements, please share.

Full JSONQuery code:

function jsonQuery(json, query) {
  var params = query.split('.'),
      result = json;

  for (var i = 0, length = params.length; i < length; ++i) {
    var parts = params[i].split('['),
        index = null;

    for (var j = 0, len = parts.length; j < len; ++j) {
      index = parts[j].replace(/\]$/, '').replace(/'/g, '');

      if (!result || !result[index])
        return null;

      result = result[index];
    }
  }

  return result;
}