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. NOTE WDDX 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> TagEach 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.
NOTE <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 PacketListing 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 ---> <html> <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.NOTE Because the MyWDDXPacket variable contains tags that look like HTML tags, most Web browsers will not display the packet's contents unless each <and> character is converted to a < or > symbol. ColdFusion's HTMLEditFormat() function escapes these types of special characters automatically, which is the reason that function is used in Listing 16.1. You can leave out this function if you want, but in that case you must use the browser's View Source command to actually see the packet's contents. Alternatively, you could use the HTMLCodeFormat() function, which would cause the browser to display the packet's contents using a fixed-width ("code") font, always on one long line. Deserializing Your First WDDX PacketListing 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 ---> <html> <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.Serializing and Deserializing Complex DataListings 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>.Listing 16.4 uses <cfwddx> to deserialize the packet and then display some of the information that it contained (see Figure 16.4). The output proves that the deserialized MyStruct variable holds exactly the same information as it did before the serialization/deserialization process. Even if the MyStruct structure contained nested structures that in turn contained other structures, or arrays that contained recordsets, you could still serialize it using the same approach. 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 ---> <html> <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<!--- Name: Deserialize2.cfm Author: Nate Weiss and Ben Forta Description: Deserialize data from a WDDX packet Created: 02/01/05 ---> <html> <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> 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. 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> |