Archive for the ‘JSON’ Category

Logging complex data with Coldfusion and JSON

Tuesday, March 2nd, 2010

Logging with Coldfusion is very simple, but in and of itself a little limiting. Generally the log itself is a string. So while logs are certainly useful for recording an action and when it happened the amount of data that is presented in the log file is fairly restrictive without doing a whole lot of work, and even then your log file may look something like: “Error occured on page #thispage.cfm# by user #john smith#. The error catch message is #an error message#. It occurred on line #230#. I’ve wrapped the dynamic content with hashes. On top of all that we’re really not saying that much here. The thing is Coldfusion gives us a ton of data nicely organized as a struct, if only we could log it.

This is just another place where JSON becomes very handy for the developer.  By serializing the struct as JSON we can log the struct as a string.  If we need to see the struct we simply need to grab the JSON and deserialize it in which case the struct will be dumpable again.  Also for debugging purposes we developers often email ourselves errors when they occur.  This is a good practice, one that I do for all my applications.  Once an application goes into production the idea is that you shouldn’t be getting that many email errors, but during development (if you’re like me) you’ll get an error email about every 3 minutes.  As you can imagine emailing a struct is a significantly larger file size than sending that same struct as JSON.  I emailed the test struct below with coldfusion as both a struct and as JSON.  The struct html was 14.4 kb.  The JSON was 0.8 kb.  That means that I can make 18 more errors for every one error that I can make now before filling up the server.

Screen shot 2010-03-02 at 7.56.24 PM

Test Struct

I created the above struct because it contains the main data types.  You can see it is a struct that contains an array, an integer, another struct, a string, and a boolean.  The struct can be created with the following code.

<cfset var data = structnew()>
<cfset data.success = true>
<cfset data.message = "This is a message.">
<cfset data.anumber = 101>
<cfset data.anarray = arrayNew(1)>
<cfset data.astruct = structnew()>

<cfloop from="1" to="10" index="VARIABLES.i">
	<cfset arrayAppend(data.anarray, VARIABLES.i)>
	<cfset data.astruct[VARIABLES.i] = VARIABLES.i + 5>
</cfloop>

(more…)

Using WDDX instead of JSON to pass string of numbers

Tuesday, March 2nd, 2010

I’m a big fan of working with JSON data, but I did run into a snag that annoyed me a little the other day. Simply put JSON takes it upon itself to convert a string of numbers to a data type number. Normally I wouldn’t notice, but in this case I was trying to return a zip code that began with a zero. Each time it was returned, the zero had been eliminated. I returned it as just a string, ran it through the tostring() method and so forth. All with no luck.

In the end I packaged the zip code in a wddx packet.  This sets the value into some xml which types it as a string if it is a string despite the fact that it is all numbers.  When the data is returned it is returned as a string, keeping the leading zero.  I’ve set up a quick demo to illustrate this issue.  If you open it in the firebug console you will be able to see the JSON that is returned in comparison to the XML in the WDDX packet.

Also remember that if you are returning structs or arrays in JSON format you can store a WDDX packet as a JSON value-pair within the struct or array.  I’ve quickly showed this below.  If there is a way to control the data typing of JSON data I’d love to know how.

<!--- SET ZIP CODE --->
<cfset var zipcode = "02906">

<!--- CREATE A STRUCT --->
<cfset var data = structnew()>
<cfset data.success = true>
<cfset data.message = "This is some type of message.">
<cfset data.zipcode = "">

<!--- SET ZIP INTO A WDDX PACKET IN THE STRUCT --->
<cfwddx action="cfml2wddx" input="#zipcode#" output="data.zipcode">

Removing extra white space before returning JSON data

Monday, February 15th, 2010

Although generating HTML in a CFC is not always good practice, when you have the choice between generating the HTML in a CFC or with jQuery it might be best to go with the CFC.  The only reason I say this is for readability and updatability.  But remember that it’s always best to create the HTML structure on the front-end page and fill in the data with Coldfusion or on the spot with jQuery and AJAX.  So enough with the disclaimers.

Sometimes it is best to return a chunk of HTML to the browser built in a CFC.  For example an application I’m working on at the moment consists of a nutritional label for a line of food products.  I of course want the same label for each product, but with different data in each label.  On top of this the label is used in several places in the application.  To add one more layer of complexity, the application is very, very AJAX dependent.  So the label is not only used in multiple places, but updates via an AJAX proxy to a CFC when the product changes.  So in this case I opted to build my label with each call inside a <cfsavecontent> tag in a remote CFC.

When I began writing the application I was getting the data for the label via AJAX and returning it to some jQuery that used the html() method to write the html with the data returned from the CFC.  It worked just fine like this.  However, it didn’t take long for the client to want to make some very minor changes.  Maybe it’s just me, but my html label in jQuery was not very readable or easy to update.  At this point I moved the entire set of HTML to the CFC and just returned a save content variable to jQuery which output the label as a single prewritten chunk of code.

Once again this was just fine until I implemented the ability for the administrator to update the data in the label.  Double-clicking a piece of the data in the label opened that data in a text field where the data could be manipulated and saved.  The problem I found was that when the data became editable in the text area it was filled with a ton of white space around the data.  So much so that the actual data could not even be seen in the text area without deleting a slew of white space.  I went back and looked at the JSON that was returned and realized that all of my indentions and line breaks I created in the CFC for readability had carried over into the JSON.  Of course, the browser ignores this white space so the label was showing correctly, but text fields do not ignore it.

So how do we remove this spacing and breaks so that it doesn’t show up in input fields and certainly not when saved to the database? As usual someone else out there has built a UDF to handle removing extra formatting. The UDF can be found at cflib.org under ‘HtmlCompressFormat(sInput)‘.  It’s a fairly simple method, but from my use seems to work very well at removing extra formatting in HTML.

The method is written in script form, and since my CFC was working in tag form I quickly rewrote it to reflect a tag based structure.  They work exactly the same and the tag based version below is simply a copy of the original script form.  To use the UDF you just need to pass in the string to remove white space from.  The method defaults to level 2 compression which I’ve found perfectly fine.  But if you did want to more or less compression you can pass in a 1, 2, or 3 after the string.

Let’s look at an example.  We have a save content variable in a cfc in which we write some nice readable indented HTML.  Everything works fine when we output it in the browser.  But if we load that HTML into a text area or rich text area we notice a whole lot of white space around the content.  When we look at the JSON that is returned from the proxy call we notice a whole lot of ‘/t/t/t/t/t/t/t/n my content /t/t/t/t/t/t/t/t/n’ going on in the code.  These are the formattings we need to get rid of.  If this string is contained in a variable called ‘mystring’ we need to run this variable through the HtmlCompressFormat() method before inserting into a database or returning to the browser.  So our method call would look something like

<!--- RUN STRING THROUGH COMPRESS HTML METHOD --->
<cfset compressedstring = HtmlCompressFormat(mystring, 2)>

So when writing dynamic HTML to be returned dynamically by jQuery I keep this method handy. Lastly, I’ll post the tag based copy of the method below. And if you want to see the original at cflib.org click here.

<cfcomponent displayname="Compress HTML" hint="Compresses any HTML passed in." output="false">

	<!--- *****************************  COMPRESS HTML  ***************************** --->
	<cffunction name="compress" displayname="Compress HTML" description="Removes any extra whitespacing in HTML." access="public" output="false" returntype="String">

		<!--- PASS IN HTML AND LEVEL OF COMPRESSION --->
		<cfargument name="htmlString" displayName="HTML String" type="string" hint="String to be compressed." required="true" />
		<cfargument name="level" displayName="Compression Level" type="numeric" hint="Level of compression" default="2" required="false" />

		<cfset var stringToCompress = ARGUMENTS.htmlString>
		<cfset var compressionLevel = ARGUMENTS.level>

		<!--- TRIM OFF ANY EXTRA SPACES FROM STRING TO BE FILTERED --->
		<cfset stringToCompress = trim(stringToCompress)>

		<!--- RUN FILTER BASED ON SPECIFIED COMPRESSION LEVEL --->
		<cfswitch expression="#compressionLevel#">
			<cfcase value="3">
				<cfset stringToCompress = reReplace(stringToCompress, "[[:space:]]{2,}", " ", "all")>
				<cfset stringToCompress = replace(stringToCompress, "> <", "><", "all")>
				<cfset stringToCompress = reReplace(stringToCompress, "<!--[^>]+>", "", "all")>
			</cfcase>

			<cfcase value="2">
				<cfset stringToCompress = reReplace(stringToCompress, "[[:space:]]{2,}", chr( 13 ), "all")>
			</cfcase>

			<cfdefaultcase>
				<cfset stringToCompress = reReplace(stringToCompress, "(" & chr( 10 ) & "|" & chr( 13 ) & ")+[[:space:]]{2,}", chr( 13 ), "all")>
			</cfdefaultcase>
		</cfswitch>

		<!--- RETURN COMPRESSED HTML --->
		<cfreturn stringToCompress>

	</cffunction>

</cfcomponent>