Click here to Skip to main content
15,883,731 members
Articles / General Programming / String

Serialize JSON Object to String

Rate me:
Please Sign up or sign in to vote.
4.20/5 (4 votes)
16 Feb 2011CPOL 35.9K   2   6
Serialize JSON Object to String

A simple way to serialize a JSON object is to iterate through the object’s property and create a JSON formatted string. All the properties and functions in a JSON object can be read just like an associative array or a name/value pair. This allows us to list all the keys and query the object for the values using the keys. Look at the following script:

JavaScript
var myJSON = {
    FirstName: '',
    LastName: '',
    Email: '',
    load: function () {
        //implementation here
    },
    serialize: function () {
        var json = "";
        for (var key in this) {
            if (typeof this[key] != 'function') {
                json += (json != "" ? "," : "") + key + ":'" + this[key] + "'";
            }
        }
        json = '[{' + json + '}]';
        return json;
    }
}

The serialize function uses a for loop to get all the keys in the object. It checks if the type is not a function because, for this case, we just want to extract the user data values and ignore the functions. You could also extract the contents of the function by just removing the if condition. To build the formatted string, the function concatenates a string with the key/value pair until it reads all the keys. The following sample script sets the property values and serializes the data to a string:

JavaScript
//client code to set properties and serialize data
if (typeof (myJSON) != 'undefined') {
    myJSON.FirstName = "myfirstname";
    myJSON.LastName = "mylastname";
    myJSON.Email = "myemail";
    var data = myJSON.serialize();
}

The data variable contains a string with this format:

C#
[{FirstName:’myfristname’,LastName:’mylastname’,Email:’myemail’}]

I hope this helps.

This article was originally posted at http://ozkary.blogspot.com/feeds/posts/default

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect OG-BITechnologies
United States United States
Software engineer, author & speaker who enjoys mentoring, learning, speaking and sharing with others about software development technologies. Microsoft MVP.

My Blog

Comments and Discussions

 
GeneralMy vote of 1 Pin
Steven Quick22-Feb-11 10:34
Steven Quick22-Feb-11 10:34 
GeneralMy vote of 5 Pin
justinonday16-Feb-11 19:41
justinonday16-Feb-11 19:41 
GeneralMy vote of 4 Pin
justinonday16-Feb-11 19:41
justinonday16-Feb-11 19:41 
GeneralMy vote of 5 Pin
ozkary16-Feb-11 3:29
ozkary16-Feb-11 3:29 
GeneralProblems with quoted strings etc Pin
jsc4215-Feb-11 6:33
professionaljsc4215-Feb-11 6:33 
Your code would fall over with quoted strings or with variable names that are not valid JavaScript variable names.

In your sample, you have myJSON.Email = "<a href="mailto:email@cn.com">email@cn.com</a>"; which will not work as you have unescaped double quotes inside a double-quoted string.

The ECMAScript 5 standard (for the next release of JavaScript) has standardised names for JSON conversions and has defined quite complex rules for how the serialisations are to be performed. Although the standard is primarily for writers of JavaScript interpretters, rather than users of JavaScript, it is useful to design methods that are compatible so that they can be thrown away when the JavaScript interpretters have native support.

I have quickly knocked together a JSON serialiser that implements many of the ECMAScript 5 capabilities. It is a little rough-and-ready but it does work for most common cases. It is future-proofed to the extent that it will not redefine native methods when they are available. One area that I haven't had time to look at in any detail is the parsing of JSON format dates - the code below is somewhat clunky; I am sure that I could do a lot more to simplify it with RegExps (this is left as an exercise for the reader!). And (as the comments indicate) the method for the first pass conversion from JSON string to a JavaScript literal has risks (the JSON string could contain executable code that would get run when it is parsed.

//	========================================================================
//	JavaScript functions to emulate the ECMAScript 5 JSON methods for 
//	non-ECMAScript 5 environments. 
//	See http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf
//
//	var ecmaobj  = JSON.parse(text [, reviver])	// Read JSON text
//		The optional reviver parameter is a function that takes two 
//		parameters, (key and value). 
//		It can filter and transform the results. 
//		It is called with each of the key/value pairs produced by the 
//		parse, and its return value is used instead of the original 
//		value. 
//		If it returns what it received, the structure is not modified. 
//		If it returns undefined then the property is deleted from the 
//		result.
//
//	var string = JSON.stringify(value[ , replacer[ , space ] ] ) 	// Convert to JSON text
//		The stringify function returns a String in JSON format 
//		representing an ECMAScript value. 
//		It can take three parameters. The first parameter is required. 
//		The value parameter is an ECMAScript value, which is usually an 
//		object or array, although it can also be a String, Boolean, 
//		Number or null. 
//		The optional replacer parameter is either a function that alters 
//		the way objects and arrays are stringified, or an array of 
//		Strings and Numbers that acts as a white list for selecting the 
//		object properties that will be stringified. 
//		The optional space parameter is a String or Number that allows 
//		the result to have white space injected into it to improve 
//		human readability.
//
//	Date.protoype.toJSON(key)	// Argument is ignored
//
if	(! JSON)	// Create static holding object
	var	JSON	= { };
//
if	(! JSON.parse)	// Create JSON parser
{
	JSON.parse	=
		function(text, optReviver)	// Result is an ecmaobj (JavaScript object)
		{
			// alert('JSON.parse(' + text + ')\nStarted'); 
			var	undefined;	// Undefined value

			// JSON literal is a subset of a JavaScript literal
			var	ecmaobj	= { };	// Result
			try
			{
				// Evaluate the literal, without using eval() (Not safe!)
				ecmaobj	= typeof text == 'string' ? (new Function("return " + text))() : text; 
			}	// try
			catch	(e)	// Rethrow the error with extra information
			{
				// alert('Caught: ' + e.message);
				throw	new Error(
						"JSON.parse: Error parsing " +  text.toString() + "\n" + 
						e.message
						); 
			}	// catch

			// If here, then the literal was parsed. Convert to permitted types. 
			for	(var p in ecmaobj)
			{
				// alert('Processing ' + p + ' (' + (typeof ecmaobj[p]) + ')');
				var	value	= ecmaobj[p]; 
				switch	(typeof value)
				{
				case	'number':
				case	'boolean':
					break;	// OK as is

				case	'string':	// Test for date literal
					if	(JSON.parse._dateRegExp.test(value))
						value	= JSON.parse._dateParse(value); 
					// else	// Leave as a string
					//	value	= value; 

					break; 

				case	'object':	// Validate elements / properties
					if	(value.constructor)
						if	(value.constructor == Array)
							for	(var i = 0; i < value.length; i++)
								value[i]	= JSON.parse(value[i], optReviver); 
						else if	(value.constructor == Date)
							value	= JSON.parse._dateParse(value); 
						else	// Other object
							value	= JSON.parse(value, optReviver);
					else if	(value == null)
						value	= value; 
					else	// Not supported
						value	= undefined;	// Discard

					break; 

				default:	// Not recognised
					value	= undefined;	// Ignore
				}	// switch

				if	(value != undefined && optReviver)
					value	= optReviver(p, value); 

				if	(value == undefined)	// Not wanted
					delete	ecmaobj[p]; 
				else	// Value could have been changed
					ecmaobj[p]	= value; 
			}	// for

			// var	x	= ''; 
			// for	(var p in ecmaobj)
			//	x	+= p + ': ' + ecmaobj[p] + ',\n';
			// alert('JSON.parse(' + text + ')\nFinished\n\n' + x); 

			return	ecmaobj; 
		};	// JSON.parse

	// String format for JSON encoded date literals
	// Dates are yyyy[-mm[-dd[Thh[:mm[:ss[.th]]][Z|+hh[mm]|-hh[mm]]]]]
	JSON.parse._dateRegExp	= 
		new RegExp(
			"^" +
				"\\d{4}" +	// yyyy
				"(-((0[1-9])|(1[0-2]))" +	// -mm
					"(-(([0-2][1-9])|([1-3]0)|31)" +	// -dd
						"(T(([01][0-9])|2[0-4])" +	// Thh
							"(:[0-5][0-9]" +	// :mm
								"(:[0-5][0-9]" +	// :ss
									"(\\.\\d*)?" +	// .th
								")?" +	// end :ss.th
							")?" +	// end :mm:ss.th
							"(Z|([+-]\\d{2}\\d{2}?))?" +	// Timezone
						")?" +	// end time
					")?" +	// end -dd
				")?" +	// end -mm
			"$"
			);	// JSON.parse._dateRegExp

	// Convert a date literal to a Date object
	JSON.parse._dateParse	= 
		function(value)
		{
			// alert('JSON.parse._dateParse(' + value + ')');
			// Parse date portion
			var	dt	= value.split('T');	// dt[0] = date string, dt[1] = time string
			// alert('dt[] = [' + dt.join(', ') + ']');
			var	yyyymmdd	= dt[0].split('-');
			// alert('yyyymmdd[] = [' + yyyymmdd.join(', ') + ']');
			switch	(yyyymmdd.length)
			{
			case	1:	// Year only
				yyyymmdd[0]	*= 1;	// Convert year to number
				yyyymmdd[1]	= 1;	// Assume Jan 1st
				yyyymmdd[2]	= 1; 
				break;

			case	2:	// Year and month
				yyyymmdd[0]	*= 1;	// Convert year and month to number
				yyyymmdd[1]	*= 1;
				yyyymmdd[2]	= 1;	// Assume 1st of month
				break;

			default:
				yyyymmdd[0]	*= 1;	// Convert year, month and day to number
				yyyymmdd[1]	*= 1;
				yyyymmdd[2]	*= 1;
				break;
			}	// switch


			// Parse time portion
			var	hhmmss	= (dt.length == 1 ? '00Z' : dt[1]).split(':'); 
			// alert('hhmmss[] = [' + hhmmss.join(', ') + ']');
			var	timezone	= "Z"; 
			switch	(hhmmss.length)
			{
			case	1:	// hh only
				timezone	= hhmmss[0].substring(2); 
				hhmmss[0]	= 1 * hhmmss[0].substring(0, 2);	// Convert hours to number
				hhmmss[1]	= 0;	// mm
				hhmmss[2]	= 0;	// ss
				hhmmss[3]	= 0;	// th
				break; 

			case	2:	// hh:mm
				timezone	= hhmmss[1].substring(2); 
				hhmmss[0]	*= 1;	// hh 
				hhmmss[1]	= 1 * hhmmss[1].substring(0, 2);	// mm
				hhmmss[2]	= 0;	// ss
				hhmmss[3]	= 0;	// th
				break; 

			default:	// hh:mm:ss[.th]
				timezone	= hhmmss[0].substring(2); 
				hhmmss[0]	*= 1;	// hh 
				hhmmss[1]	*= 1;	// mm
				var	t	= // Find optional timezone separator char
					Math.min(
						(hhmmss[2] + 'Z').indexOf('Z'), 
						Math.min(
							(hhmmss[2] + '+').indexOf('+'), 
							(hhmmss[2] + '-').indexOf('-')
							)
						); 
				timezone	= hhmmss[2].substring(t); 
				hhmmss[3]	= parseFloat(hhmmss[2].substring(0, t)); 
				hhmmss[2]	= Math.floor(hhmmss[3]);	// ss
				hhmmss[3]	-= hhmmss[2];	// 1/1000th sec
				break; 
			}	// switch

			// Adjust time based on timezone
			switch	(timezone.charAt(0))
			{
			case	'+':
				hhmmss[0]	+= 1 * timezone.substring(1, 3);	// Hours offset
				hhmmss[1]	+= 1 * (timezone + '00').substring(3, 5);	// Minutes offset
				break; 

			case	'-':
				hhmmss[0]	-= 1 * timezone.substring(1, 3);	// Hours offset
				hhmmss[1]	-= 1 * (timezone + '00').substring(3, 5);	// Minutes offset
				break; 

			default:	// Z or missing
				break; 
			}	// switch

			// alert('Date:\n\n' + [ 
			//	yyyymmdd[0], yyyymmdd[1] - 1, yyyymmdd[2], 
			//	hhmmss[0], hhmmss[1], hhmmss[2], hhmmss[3] * 1000
			//	].join(',')
			//	);
			return	new Date(
					Date.UTC(
						yyyymmdd[0], yyyymmdd[1] - 1, yyyymmdd[2], 
						hhmmss[0], hhmmss[1], hhmmss[2], hhmmss[3] * 1000
						)
					); 
		};	// JSON.parse._dateParse
	};	// if
//
if	(! JSON.stringify)	// Create JSON toString method
{
	JSON.stringify	=
		function(value, optReplacer, optSpace)	// Result is a string
		{
			// See if a property is to be output or not
			var	undefined;	// Undefined value

			var	isWanted	= 
				function(name)
				{
					// See if the name is on the whitelist
					var	wanted	= false;
					if	(optReplacer && optReplacer.constructor && optReplacsr.constructor == Array)
						for	(var i = 0; i < optReplacer.length && ! wanted; i++)
							wanted	= name == optReplacer[i].toString(); 
					else
						wanted	= true;	// No whitelist

					// Ensure that the type of value is permitted
					if	(wanted)
						switch	(typeof value[p])
						{
						case	'boolean':
						case	'number':
						case	'object':	// Includes Date and Array
						case	'string':
							break;	// Wanted types

						default:	// Not on the permitted list
							wanted	= false;
						}	// switch

					return	wanted;
				};	// isWanted

			// Convert optSpace to a separator string
			if	(optSpace)
				if	(typeof optSpace == 'number')
				{
					// Convert to a string of space chars
					var	temp	= '                '; 
					while	(temp.length < optSpace)
						temp	+= temp; 

					optSpace	= temp.substring(0, optSpace); 
				}	// if
				else	// Assume value is a text
					optSpace	= optSpace.toString ? optSpace.toString() : ' ';
			else
				optSpace	= '\n\t';

			// Convert value
			var	output	= [ ];	// Collection of values
			if	(value == undefined)
				return	'undefined'; 
			else if	(typeof value == 'object')
				if	(typeof optReplacer == 'function')
					return	optReplacer(value); 
				else if	(value == null)
					return	'null';
				else if	(value.constructor && value.constructor == Date)
					return	'"' + value.toJSON() + '"'; 
				else if	(value.constructor && value.constructor == Array)
				{
					for	(var i = 0; i < value.length; i++)
						output[i]	= JSON.stringify._toJSONString(value[i], optReplacer, optSpace); 

					return	'[' + optSpace + output.join(',' + optSpace) + optSpace + ']';
				}	// else if
				else	// Normal object
				{
					for	(var p in value)
						if	(isWanted(p))
							output[output.length]	= 
								(	(/^[a-z_$][a-z0-9_$]*$/i).test(p)
								?	p	// Name is valid JavaScript var name
								:	"'" + p.replace(/'/g, "\\'") + "'"	// Invalid name. Make quoted string
								) +
								': ' +
								JSON.stringify._toJSONString(value[p], optReplacer, optSpace); 

					return	'{' + optSpace + output.join(',' + optSpace) + optSpace + '}';
				}	// else
			else
				return	value.toString ? value.toString() : typeof value; 
		};	// JSON.strignify

	// Convert a value to a JSON string
	JSON.stringify._toJSONString	= 
		function(value, optReplacer, optSpace)
		{
			// Convert number to 2 hex digits
			var	hexDigits	= '0123456789ABCDEF'; 
			var	hex2	= 
				function(n)
				{
					return	hexDigits.charAt(n >> 4) + hexDigits.charAt(n & 0xF);
			 	};	// hex2

			// Convert based on type of item
			switch	(typeof value)
			{
				case	'boolean':
					return	value ? 'true' : 'false';

				case	'number':
					return	value.toString(); 

				case	'string':
					// Escape special characters
					var	str	= 
						value	// Convert JSON escaped chars
							.replace(/\\/g, '\\\\')
							.replace(/\//g, '\\/')
							.replace(/"/g, '\\"')
							.replace(/[\b]/g, '\\b')	// \b is only a backspace inside [ and ]
							.replace(/\f/g, '\\f')
							.replace(/\n/g, '\\n')
							.replace(/\r/g, '\\r')
							.replace(/\t/g, '\\t'); 

					// Escape any Unicode chars
					for	(var i = 0; i < str.length; i++)
					{
						var	charCode	= str.charCodeAt(i); 
						if	(charCode >= 256)	// Unicode char
						{
							str.replace(str.charAt(i), '\\u' + hex2(charCode >> 8) + hex2(charCode & 0xFF)); 
							i	+= 5; 
						}	// if
						else if	(charCode < 32 || charCode > 127)	// Special ASCII char
						{
							str.replace(str.charAt(i), '\\x' + hex2(charCode)); 
							i	+= 3; 
						}	// else if
					}	// for

					return	'"' + str + '"'; 

				case	'object':	// Includes null, Array, and Date
					return	JSON.stringify(value, optReplacer, optSpace); 

				default:	// Unsupported
					return	'undefined';
			}	// switch
		};	// JSON.stringify._toJSONString
}	// if
//
if	(! Date.prototype.toJSON)
	Date.prototype.toJSON	=	// This version returns date in UTC (Timezone Z) format
		function(key)
		{
			return	this.getUTCFullYear() +	// yyyy (Always 4 chars)
				'-' + (101 + this.getUTCMonth()).toString().substring(1) +	// -mm
				'-' + (100 + this.getUTCDate()).toString().substring(1) +	// -dd
				'T' + (100 + this.getUTCHours()).toString().substring(1) +	// Thh
				':' + (100 + this.getUTCMinutes()).toString().substring(1) +	// :mm
				':' + (100 + this.getUTCSeconds()).toString().substring(1) +	// :ss
				(	this.getUTCMilliseconds()	// Milliseconds is optional
				?	'.' + (1000 + this.getUTCMilliseconds()).toString().substring(1)	// .th
				:	''
				) +
				'Z';	// Always UTC
		};	// Date.prototype.toJSON
//

GeneralRe: Problems with quoted strings etc Pin
ozkary15-Feb-11 9:19
ozkary15-Feb-11 9:19 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.