Using WDDX with ColdFusion
Now that you have an idea what WDDX is all about, you can start learning how to use it in your ColdFusion applications. This section introduces you to the <cfwddx> tag and gets you thinking about different ways you can use WDDX in your own pages. You will find that WDDX is a very flexible technology, appropriate for solving many types of problems, from simple to complex, lofty to mundane.NOTEWDDX is not just for ColdFusion developers. The same basic techniques explained in this book can be used within Java, Perl, and more. And data that has been converted to WDDX can almost always be effortlessly shared between any of these applications with no loss of integrity.
Introducing the <cfwddx> Tag
Each language or environment that supports WDDX has some way to serialize and deserialize WDDX packets. In ColdFusion, it's the <cfwddx> tag. You use <cfwddx> to serialize data from native CFML variables to the WDDX packet format. You also use it to deserialize the data from the WDDX packet back into native ColdFusion variables.First, I'll show you how to use the <cfwddx> tag to do some simple serialization and deserialization of WDDX packets. Then we'll take a closer look at what the actual packets look like. The first thing for you to understand is the syntax supported by the <cfwddx> tag, as outlined in Table 16.1.
ATTRIBUTE | DESCRIPTION |
---|---|
actio | Required. Specifies whether to convert to or from the WDDX format. Use action="cfml2wddx" to serialize a ColdFusion variable to a WDDX packet. Use action="wddx2cfml" to deserialize a WDDX packet back into a native ColdFusion variable. |
input | Required. The value to be converted. If you are using action="cfml2wddx", here is where you provide the value you want to serialize. If you are using action="wddx2cfml", provide the WDDX packet you want to deserialize. |
OUTPUT | The name of a variable to hold the result of the conversion. If you are using action="cfml2wddx", the serialized WDDX packet will be stored in the variable you specify here. If you are using action="wddx2cfml", the data from the WDDX packet will be deserialized and stored in this variable. |
usetimezoneinfo | Optional. Relevant only when deserializing data with action="wddx2cfml". If Yes (the default) and the WDDX packet contains dates that contain time zone information, ColdFusion will convert the dates to the server's time zone during the deserialization process. If No, all time zone information in the packet is ignored. |
validate | Optional. Relevant only when deserializing data with action="wddx2cfml". If No (the default), it is assumed that the packet provided to the input attribute is known to be a valid WDDX packet. If Yes, the packet is checked for validity first, which adds a small amount of overhead. In general, the IsWDDX() function is a better way to make sure a packet is valid; for details, see the section "Validating Packets with IsWDDX()" later in this chapter. |
<cfwddx> supports two other action values, as well (cfml2js and wddx2js), and one more attribute (toplevelvariable). These items are all specific to using ColdFusion with JavaScript and are discussed in Chapter 17, "Using JavaScript and ColdFusion Together."
Creating Your First WDDX Packet
Listing 16.1 shows how to use <cfwddx> to serialize a simple string value into a WDDX packet. This listing then displays the packet and also saves the packet to the server's drive as a file called StringPacket.txt (see Figure 16.1).
Listing 16.1. Serialize1.cfmConverting a Simple String to WDDX
<!---
Name: Serialize1.cfm
Author: Nate Weiss and Ben Forta
Description: Serialize data into a WDDX packet
Created: 02/01/05
--->
&l233>
<head>
<title>WDDX Demonstration</title>
</head>
<body>
<!--- set the #message# variable to a simple string value --->
<cfset Message="Hello, World!">
<!--- Serialize the #Message# variable into a WDDX Packet --->
<cfwddx action="CFML2WDDX"
input="#Message#"
output="MyWDDXPacket">
<!--- Output WDDX packet so we can see what it looks like --->
<!--- (HTMLEditFormat function lets us see tags properly) --->
<cfoutput>
<p><strong>Original Message:</strong> #Message#</p>
<p><strong>The message was serialized into
the following WDDX packet:</strong></p>
#HTMLEditFormat(MyWDDXPacket)#
</cfoutput>
<!--- Save the WDDX packet to a file on the server's drive --->
<cffile action="WRITE"
file="#ExpandPath('StringPacket.txt')#"
output="#MyWDDXPacket#">
</body>
</html>
Figure 16.1. Simple strings get placed between <string> tags in the WDDX format.
<and> character is converted to a < or > symbol. ColdFusion's
Deserializing Your First WDDX Packet
Listing 16.2 shows how to deserialize a WDDX packet. As you can see, the process is very similar to the serialization process; you just use action="wddx2cfml" instead of action="cfml2wddx" in the <cfwddx> tag, and supply the text of the WDDX packet as the tag's input attribute.Whatever is stored in the WDDX packet will become available in the variable you specify in the output attribute. In this case, the contents of the packet is the "Hello, World" message from Listing 16.1. So, after the <cfwddx> tag, the Message variable contains that string and can be displayed in a <cfoutput> block just like any other string variable (see Figure 16.2).
Listing 16.2. Deserialize1.cfmDeserializing the Packet Created with Listing 16.1
<!---
Name: Deserialize1.cfm
Author: Nate Weiss and Ben Forta
Description: Deserialize data from a WDDX packet
Created: 02/01/05
--->
&l233>
<head>
<title>WDDX Demonstration</title>
</head>
<body>
<!--- Read the WDDX packet from the file on the server's drive --->
<cffile action="READ"
file="#ExpandPath('StringPacket.txt')#"
variable="MyWDDXPacket">
<!--- Deserialize the WDDX packet back into native #Message# variable --->
<cfwddx action="WDDX2CFML"
input="#MyWDDXPacket#"
output="Message">
<cfoutput>
<!--- Display the message we retrieved from the WDDX packet --->
<p><strong>Deserialized Message:</strong> #Message#</p>
<p><strong>The message was deserialized from
the following WDDX packet:</strong></p>
<!--- Output WDDX packet so we can see what it looks like --->
<!--- (HTMLEditFormat function lets us see tags properly) --->
#HTMLEditFormat(MyWDDXPacket)#
</cfoutput>
</body>
</html>
Figure 16.2. You can easily deserialize any WDDX packet with the <CFWDDX> tag.
[View full size image]

Serializing and Deserializing Complex Data
Listings 16.1 and 16.2 showed you how to serialize and deserialize a simple string value. Although those listings are a useful demonstration of the <cfwddx> tag, the actual result is not that interesting. Those listings simply stored a string value in a file; you could have achieved that result by saving the string to a simple text file with the <cffile> tag alone.Things get a lot more interesting when you use <cfwddx> to serialize and deserialize complex data types such as arrays, query recordsets, and structures. In fact, just about any CFML variable can be serialized (and then deserialized) with WDDX, and the <cfwddx> tag syntax remains exactly the same.Listing 16.3 creates a structure called MyStruct, fills it with various types of data (including a nested array and a nested query recordset), and serializes it with the <cfwddx> tag (see Figure 16.3). The packet is stored in a text file called StructPacket.txt.
Figure 16.3. Complex values such as structures, recordsets, and arrays can be serialized with <cfwddx>.
[View full size image]

Listing 16.3. Serialize2.cfmSerializing a Structure that Contains an Array and Recordset
<!---
Name: Serialize2.cfm
Author: Nate Weiss and Ben Forta
Description: Serialize data into a WDDX packet
Created: 02/01/05
--->
&l233>
<head>
<title>WDDX Demonstration</title>
</head>
<body>
<!--- Run a simple database query to include in the WDDX packet --->
<!--- Limit the query to just 5 rows to keep things simple --->
<cfquery name="filmsquery" datasource="ows" maxrows="5">
SELECT FilmID, MovieTitle, AmountBudgeted, DateInTheaters
FROM Films
ORDER BY MovieTitle
</cfquery>
<!--- Create a structure --->
<cfset MyStruct=StructNew()>
<!--- Add a few simple string values --->
<cfset MyStruct.CompanyName="Orange Whip Studios">
<cfset MyStruct.CompanyURL="http://www.orangewhipstudios.com">
<!--- Add the current date and time --->
<cfset MyStruct.PacketDate=Now()>
<!--- Add the contents of the FilmsQuery query --->
<cfset MyStruct.Films=FilmsQuery>
<!--- Add a simple array --->
<cfset MyStruct.Offices=ArrayNew(1)>
<cfset MyStruct.Offices[1]="New York, NY">
<cfset MyStruct.Offices[2]="Paris, France">
<cfset MyStruct.Offices[3]="Pittsfield, MA">
<!--- Serialize the #MyStruct# structure into a WDDX Packet --->
<cfwddx action="CFML2WDDX"
input="#MyStruct#"
output="MyWDDXPacket">
<!--- Output WDDX packet so we can see what it looks like --->
<!--- (HTMLEditFormat function lets us see tags properly) --->
<cfoutput>
<p><strong>The structure was serialized into the
following WDDX packet:</strong></p>
#HTMLEditFormat(MyWDDXPacket)#
</cfoutput>
<!--- Save the WDDX packet to a file on the server's drive --->
<cffile action="WRITE"
file="#ExpandPath('StructPacket.txt')#"
output="#MyWDDXPacket#">
</body>
</html>
Figure 16.4. After deserialization, the data from a WDDX packet can be used just like any other data.

Listing 16.4. Deserialize2.cfmDeserializing a Multifaceted Data Structure
It's worth emphasizing that <cfwddx> doesn't care what a variable contains when you serialize it. You feed it whatever data you want converted to a packet, and it obliges. Compare this to traditional XML approaches, with which you would normally have to decide on what tag and attribute names you wanted to use, perhaps creating a DTD along the way, and then populate an XML document using DOM-like syntax. Don't get me wrong here. I'm not trying to suggest that WDDX is better than other types of XML. But WDDX is unquestionably easier to use for quick-and-dirty tasks where all you want to do is convert data to XML in a quick and reliable fashion.
<!---
Name: Deserialize2.cfm
Author: Nate Weiss and Ben Forta
Description: Deserialize data from a WDDX packet
Created: 02/01/05
--->
&l233>
<head>
<title>WDDX Demonstration</title>
</head>
<body>
<!--- Read the WDDX packet from the file on the server's drive --->
<cffile action="READ"
file="#ExpandPath('StructPacket.txt')#"
variable="MyWDDXPacket">
<!--- Deserialize the WDDX packet back into native #MyStruct# variable --->
<cfwddx action="WDDX2CFML"
input="#MyWDDXPacket#"
output="MyStruct">
<!--- Output various information from the packet, to prove that --->
<!--- the structure contains all of the original information --->
<cfoutput>
<!--- MyStruct.CompanyName should be a string value --->
<strong>Company name:</strong>
#MyStruct.CompanyName#<br>
<!--- MyStruct.Offices should be an array --->
<strong>Number of offices:</strong>
#ArrayLen(MyStruct.Offices)#<br>
<!--- MyStruct.PacketDate should be a date/time object --->
<strong>Information recorded at:</strong>
#DateFormat(MyStruct.PacketDate)# #TimeFormat(MyStruct.PacketDate)#<br>
<!--- MyStruct.Films should be a query recordset --->
<p><strong>Films:</strong><br>
<cfloop query="MyStruct.Films">
#MovieTitle#<br>
</cfloop>
</cfoutput>
</body>
</html>
Validating Packets with IsWDDX()
Sometimes you'll want to deserialize packets that may be coming from some other application or location. If you're unsure whether a WDDX packet is valid, you can use the IsWDDX() function to validate it before attempting to deserialize it with the <cfwddx> tag.The IsWDDX() function accepts a single argument, which is the string value that you suspect to be a WDDX packet. The function returns TRue or false, depending on whether the packet is indeed valid. If the result is false, the packet cannot be deserialized with <cfwddx>.For instance, you could add the following <cfif> block to Listing 16.4, after the <cffile> tag but before the <cfwddx> tag:
<!--- Make sure the packet is valid before deserializing it --->
<cfif not IsWDDX(MyWDDXPacket)>
Sorry, the StructPacket.txt file does not contain a valid WDDX packet.
<cfabort>
</cfif>