The Cache: Technology Expert's Forum
 
*
Welcome, Guest. Please login or register.
Did you miss your activation email?
May 25, 2012, 05:15:13 AM

Login with username, password and session length


Pages: [1]
  Print  
Author Topic: JSON Encoder for Javascript  (Read 6101 times)
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 9896



View Profile
« on: July 29, 2008, 01:47:43 PM »

OK, so you're sending data to a client via AJAX and JSON. Now, you want to send a big multipli-nested array back up to the server. So, where's the json_encode for Javascript?

There isn't one. That's because the JSON notation was written for loading objects up in Javascript, not preparing them for AJAX. So this little chunk repairs that small but significant oversite. It uses reentrance to be fast and will handle normal indexed arrays and associative arrays. You simply say, var myStr = json_encode(theArr) and you're all set.

Enjoy!

/p

Code:
function json_encode(inVal) { return _json_encode(inVal).join(''); }
function _json_encode(inVal, out)
{
out = out || new Array();
var undef; // undefined
switch (typeof inVal)
{
case 'object':
if (!inVal)
{
out.push('null');
} else {
if (inVal.constructor == Array)
{
// Need to make a decision... if theres any associative elements of the array
// then I will block the whole thing as an object {} otherwise, I'll block it
// as a  normal array []
var testVal = inVal.length;
var compVal = 0;
for (var key in inVal) compVal++;
if (testVal != compVal)
{
// Associative
out.push('{');
i = 0;
for (var key in inVal)
{
if (i++ > 0) out.push(',\n');
out.push('"');
out.push(key);
out.push('":');
_json_encode(inVal[key], out);
}
out.push('}');
} else {
// Standard array...
out.push('[');
for (var i = 0; i < inVal.length; ++i)
{
if (i > 0) out.push(',\n');
_json_encode(inVal[i], out);
}
out.push(']');
}

} else if (typeof inVal.toString != 'undefined') {
out.push('{');
var first = true;
for (var i in inVal)
{
var curr = out.length; // Record position to allow undo when arg[i] is undefined.
if (!first) out.push(',\n');
_json_encode(i, out);
out.push(':');                   
_json_encode(inVal[i], out);
if (out[out.length - 1] == undef)
{
out.splice(curr, out.length - curr);
} else {
first = false;
}
}
out.push('}');
}
}
return out;

case 'unknown':
case 'undefined':
case 'function':
out.push(undef);
return out;

case 'string':
        out.push('"');
        out.push(inVal.replace(/(["\\])/g, '\$1').replace(/\r/g, '').replace(/\n/g, '\n'));
        out.push('"');
        return out;
       
default:
out.push(String(inVal));
return out;
}
}
« Last Edit: July 29, 2008, 02:53:43 PM by perkiset » Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 9896



View Profile
« Reply #1 on: July 29, 2008, 01:49:11 PM »

And another version:

If you're shipping this function out via PHP, then there will be problems with the regexs because of the PHP parser. The following version of the function is ok to do a HEREDOC and output to your client via PHP:

Code:
<?php

$stript 
= <<<JS
function json_encode(inVal) { return _json_encode(inVal).join(''); }
function _json_encode(inVal, out) 
{
out = out || new Array();
var undef; // undefined
switch (typeof inVal)
{
case 'object':
if (!inVal) 
{
out.push('null');
} else {
if (inVal.constructor == Array) 
{
// Need to make a decision... if theres any associative elements of the array
// then I will block the whole thing as an object {} otherwise, I'll block it 
// as a  normal array []
var testVal = inVal.length;
var compVal = 0;
for (var key in inVal) compVal++;
if (testVal != compVal)
{
// Associative
out.push('{');
i = 0;
for (var key in inVal)
{
if (i++ > 0) out.push(',\\n');
out.push('"');
out.push(key);
out.push('":');
_json_encode(inVal[key], out);
}
out.push('}');
} else {
// Standard array...
out.push('[');
for (var i = 0; i < inVal.length; ++i) 
{
if (i > 0) out.push(',\\n');
_json_encode(inVal[i], out);
}
out.push(']');
}

} else if (typeof inVal.toString != 'undefined') {
out.push('{');
var first = true;
for (var i in inVal) 
{
var curr = out.length; // Record position to allow undo when arg[i] is undefined.
if (!first) out.push(',\\n');
_json_encode(i, out);
out.push(':');                    
_json_encode(inVal[i], out);
if (out[out.length - 1] == undef)
{
out.splice(curr, out.length - curr);
} else {
first = false;
}
}
out.push('}');
}
}
return out;

case 'unknown':
case 'undefined':
case 'function':
out.push(undef);
return out;

case 'string':
        out.push('"');
        out.push(inVal.replace(/(["\\\])/g, '\\$1').replace(/\\r/g, '').replace(/\\n/g, '\\n'));
        out.push('"');
        return out;
        
default:
out.push(String(inVal));
return out;
}
}
JS;
?>


/p
Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
nutballs
Administrator
Lifer
*****
Offline Offline

Posts: 5627


Back in my day we had 9 planets


View Profile
« Reply #2 on: July 29, 2008, 02:23:59 PM »

cool thanks. I was just about to post a question asking about this lol.
Logged

I could eat a bowl of Alphabet Soup and shit a better argument than that.
vsloathe
vim ftw!
Global Moderator
Lifer
*****
Offline Offline

Posts: 1669



View Profile
« Reply #3 on: July 29, 2008, 03:11:18 PM »

very nice sir. tyvm
Logged

hai
sgrew2009
n00b
*
Offline Offline

Posts: 2


View Profile
« Reply #4 on: November 01, 2009, 09:28:25 AM »

Note: [updated post - source code formatting]

Nice script.

I am using it with MooTools as their json encode function doesn't appear to do what I want...

Problem is that MooTools extends the arrays and when you run the json_encode() script listed here against the array, it encodes all of the extensions into the json string.

I modified it using the suggestion at http://onwebdevelopment.blogspot.com/2008/01/prototype-mootools-etc-breaking-for-in.html to deal with this behaviour.

I added either the "if (inVal.hasOwnProperty(key)){}"  or   "if (inVal.hasOwnProperty(i)){}" wrapper around the contents of the for .. in and for () loops in order to eliminate the extensions to the array from being processed. I have only applied it to the data I am working with so it has not had extensive testing. It works to fix the problem created by the MooTools extensions on my site.

Here is the code as I have modified it in case it is of use to anyone else. No warranty or suggestion that it works on any site other than my own... usual disclaimer... :-)

The format has been changed to the standard that I use... so it looks a little bit different...

NOTE: This POST has been updated to fix the code tags around the source code. Thank you for suggesting that!

START OF MODIFIED VERSION
Code:
/**
 * JSON Encoder for JavaScript
 *
 * Modified : 2009.11.01 to work with MooTools Enhanced Arrays
 *
 * Modification consists of addition of the tests :
 *   if (inVal.hasOwnProperty(key)) {}
 *   if (inVal.hasOwnProperty(i)) {}
 *
 * These are the tests that make the encoder ignore the MooTools array extensions.
 *
 * Original code found at :
 *   http://www.perkiset.org/forum/javascript/json_encoder_for_javascript-t1094.0.html
 *
 */

function json_encode(inVal) { return _json_encode(inVal).join(''); }
function _json_encode(inVal, out)
  {
    out = out || new Array();
    var undef; // undefined
    switch (typeof inVal)
      {
        case 'object':
          if (!inVal)
            {
              out.push('null');
            }
          else
            {
              if (inVal.constructor == Array)
                {
                  // Need to make a decision... if theres any associative
                  // elements of the array then I will block the whole
                  // thing as an object {} otherwise, I'll block it
                  // as a  normal array []
                  var testVal = inVal.length;
                  var compVal = 0;
                  for (var key in inVal)
                    {
                      if (inVal.hasOwnProperty(key))
                        {
                          compVal++;
                        }
                    }
                  if (testVal != compVal)
                    {
                      // Associative
                      out.push('{');
                      i = 0;
                      for (var key in inVal)
                        {
                          if (inVal.hasOwnProperty(key))
                            {
                              if (i++ > 0) out.push(',\n');
                              out.push('"');
                              out.push(key);
                              out.push('":');
                              _json_encode(inVal[key], out);
                            }
                        }
                      out.push('}');
                    }
                  else
                    {
                      // Standard array...
                      out.push('[');
                      for (var i = 0; i < inVal.length; ++i)
                        {
                          if (inVal.hasOwnProperty(i))
                            {
                              if (i > 0) out.push(',\n');
                              _json_encode(inVal[i], out);
                            }
                        }
                      out.push(']');
                    }

                }
              else
                {
                  if (typeof inVal.toString != 'undefined')
                    {
                      out.push('{');
                      var first = true;
                      for (var i in inVal)
                        {
                          if (inVal.hasOwnProperty(i))
                            {
                              var curr = out.length; // Record position to allow undo when arg[i] is undefined.
                              if (!first) out.push(',\n');
                              _json_encode(i, out);
                              out.push(':');                   
                              _json_encode(inVal[i], out);
                              if (out[out.length - 1] == undef)
                                {
                                  out.splice(curr, out.length - curr);
                                }
                              else
                                {
                                  first = false;
                                }
                            }
                        }
                      out.push('}');
                    }
                }
            }
          return out;

        case 'unknown':
        case 'undefined':
        case 'function':
          out.push(undef);
          return out;

        case 'string':
          out.push('"');
          out.push(inVal.replace(/(["\\])/g, '\$1').replace(/\r/g, '').replace(/\n/g, '\n'));
          out.push('"');
          return out;
       
        default:
          out.push(String(inVal));
          return out;
      }
  }
END OF MODIFIED VERSION


« Last Edit: November 09, 2009, 07:47:41 PM by sgrew2009 » Logged

No links in signatures please
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 9896



View Profile
« Reply #5 on: November 01, 2009, 11:03:55 PM »

Thanks for the update screw ... and welcome to the Cache Smiley

I noticed that about midway through the script it switched to italics, which would mean most likely that you referenced an array sub indexed i ... in other words, [ i ] which, to SMF means start italic. I can pretty well see where it was, but in the interest of making sure that your code is correct and nothing else got squirreled, I wonder if I could bother you to repost it, but please put it between [ code] and [ / code] (no spaces) so that SMF doesn't munge your work.

Thanks again!
/perk
Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
sgrew2009
n00b
*
Offline Offline

Posts: 2


View Profile
« Reply #6 on: November 09, 2009, 07:46:02 PM »

Hi !
I updated my original post to fix the source code layout.

that is sgrew, by the way, with a g ... :-)
« Last Edit: November 09, 2009, 07:48:58 PM by sgrew2009 » Logged

No links in signatures please
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 9896



View Profile
« Reply #7 on: November 09, 2009, 07:49:55 PM »

that is sgrew, by the way, with a g ... :-)

ROFLMAO ROFLMAO ROFLMAO ROFLMAO Whadda maroon! Sorry meng. My bad.
Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
Pages: [1]
  Print  
 
Jump to:  

Perkiset's Place Home   Best of The Cache   phpMyIDE: MySQL Stored Procedures, Functions & Triggers
Politics @ Perkiset's   Pinkhat's Perspective   
cache
mart
coder
programmers
ajax
php
javascript
Powered by MySQL Powered by PHP Powered by SMF 1.1.2 | SMF © 2006-2007, Simple Machines LLC
Seo4Smf v0.2 © Webmaster's Talks


Valid XHTML 1.0! Valid CSS!