views:

732

answers:

3

Anyone know of a good way to convert a JSON object to nested form fields? For example, given I have the JSON object

{'a':{'b':{'c':'1200'}}}, 'z':'foo', 'bar':{'baz':'1', 'id':2}}

I should get

{'a[b][c]':'1200', 'z':'foo', 'bar[baz]':'1', 'bar[id]':2};

Any ideas? I am currently using jquery and it feels like something like this already exists, if not I can simply roll my own with a crazy algorithm, but I'd rather use something with a proven track record.

+1  A: 

So, I have no clue why you want to do what you say you want to do, and I hope you will fill us all in, but this code should be close enough for you to be able to tweak it (this is based on some code of mine that I use to find differences in JavaScript object graphs):

function doStrangeThing(obj) {
   var propertyChanges = [];
    var objectGraphPath = [];
    (function(obj, refObj) {
        if ( obj.constructor == Object || (obj.constructor != Number &&
             obj.constructor != String && obj.constructor != Date && obj.constructor != Boolean &&
             obj.constructor != RegExp && obj.constructor != Function)) {
            for (var property in obj) {
                objectGraphPath.push((objectGraphPath.length > 0) ? "[" + property + "]" : property);
                if (obj[property].constructor != Function) {
                    if (!refObj[property]) refObj[property] = {};
                    arguments.callee(obj[property], refObj[property]);
                }
                objectGraphPath.pop();
            }
        } else if (obj.constructor != Function) {
            if (obj != refObj) {
                propertyChanges.push("\"" + objectGraphPath.join("") + "\":\"" + obj.toString() + "\"");
            }
        }
    })(obj, {});
    return "{" + propertyChanges.join(",") + "}";
}

Here is what I did to test it:

doStrangeThing({'a':{'b':{'c':'1200'}}, 'z':'foo', 'bar':{'baz':'1', 'id':2}});

Which results in this value:

{"a[b][c]":"1200","z":"foo","bar[baz]":"1","bar[id]":"2"}

Hope that is useful to you in some way...

Jason Bunting
once this reaches the serverside, in php it becomes a nested hash map.
Well, if it works for you, please mark it as the answer - I don't know anything about PHP or the need for this, but obviously you have your reasons. :) Again, it could probably use a little tweaking to make it do things EXACTLY as you would like it to, but this was relatively quick for me to test and play with, since I had written this code quite a while ago...
Jason Bunting
When I say "tweak," by the way, I mean to get the value types working correctly - I see that you wanted the value of "bar[id]" to be the literal number 2, not a string ("2") - you could tweak the code to test to see if something is a number and if so, not use quotations; etc.
Jason Bunting
Jason Bunting: +1 for doing it for free. I know how that's ironic. :)
Tomalak
@unknown (yahoo): Since you seem to have jQuery at you disposal, I feel obliged to tell you that you may be better off sending JSON to the server (http://code.google.com/p/jquery-json/) and have PHP evaluate the JSON (http://de.php.net/manual/en/function.json-decode.php). I would say that this has the type of track record you were looking for.
Tomalak
@Tomalak: Yeah, I have to assume the OP knows what he/she is doing, because the results he requested look like useless @*$!! to me. I feel an inkling that there is a better way to do what he is intended on doing with this than to do it this way, but I thought it would be "fun" to see if I could get it to work, as nightmarish as it looks. :)
Jason Bunting
A: 
obj = {'a':{'b':{'c':'1200'}}}, 'z':'foo', 'bar':{'baz':'1', 'id':2}}

is internally equivalent to

{['a']['b']['c']:'1200', ['z']:'foo', ['bar']['baz']:'1', ['bar']['id']:2}

Please note that this is not JSON object anymore.

You already can refer first object properties in this way:

var z = obj['a']['b']['c']   // 1200

Is it enough for your needs? Do you really want to convert property names to variables?

Thevs
I had to laugh when I read this answer because I think I sense the same feeling I had when I read the question - i.e. WTF is this guy going to do with this mess?! It was an interesting exercise nonetheless, but I don't know what "unknown" is doing with this stuff in PHP. Weird stuff.
Jason Bunting
Actually, I got what he wanted. Quite weird, but it have some sence. However, there are plenty of simpler algorithmic ways to achieve the same goal... And there would be a big mess with variable names and namespaces, if it should have been implemented for common usage.
Thevs
A: 

I would actually recommend a function that takes a nested JSON object and turns it into a HTTP POST string. jQuery will accept that for all of its arguments that require HTTP parameters.

I have written and used the function below in several production apps (use at your own risk):

$.httpSerialize = function(items, parentName) {
 var serializedItems = [], serialize = arguments.callee, encodeItem =  function(key, value) {
  if (value === null || typeof value == 'undefined') return value;
  if (value.constructor == Array) {return serialize(value, key);}
  return (value.constructor == Object)
   ? serialize(value, key)
   : (value === true || value === false)
    ? key+"="+new Number(value)
    : key+"="+encodeURIComponent(value);
 };

 if (items.constructor == Array) {
  parentName = parentName || 'item';
  for (var i = 0; i < items.length; i++) {
   var key = parentName+'['+i+']', value = items[i];
   serializedItems.push(encodeItem(key, value));
  }
 } else {
  parentName = parentName || '';
  for (var key in items) {
   var value = items[key];
   if (parentName) {
    serializedItems.push(encodeItem(parentName+'['+encodeURIComponent(key)+']', value));
   } else {
    serializedItems.push(encodeItem(encodeURIComponent(key), value));
   }
  }
 }
 return serializedItems.join("&");
};
felixge