WDDX is an XML vocabulary and technology that was developed by Allaire in 1998 for describing a complex data structure such as an array, an associative array (that is, ColdFusion structs), or a recordset in a generic fashion. WDDX was developed to be an open method for exchanging complex data between a variety of applications and languages, and it is currently supported in ASP, ColdFusion, Java, Python, Perl, Flash, PHP, and Tcl/Tk! WDDX offers developers several advantages over creating their own XML language for exchanging data: It's already well supported, is very lightweight, and is extremely easy to use. You need to have almost zero knowledge of XML to use it. Note Check out www.openwddx.org. This is the WDDX site where you can download the WDDX DTD and SDK. You can also find answers to numerous questions in its forums and email list. WDDX supports two very basic concepts for information exchange. The first of these is serialization of data from its native format (that is, a query recordset) into a WDDX XML format. The second is deserialization, or the transformation from a WDDX XML document into a native data type such as a CFML structure or a Java associative array. In ColdFusion, you work with WDDX via the CFWDDX tag, which supports the following functions
A typical CFWDDX tag used to convert a CFML query object to WDDX looks like this: <cfwwdx action="cfml2wddx" input="#MyQueryObject#" output="WddxTextVariable"> In this example, MyQueryObject is the name of the query object variable, and WddxTextVariable is the name of the variable in which to store the resulting WDDX XML. Validating WDDX DataThe CFWDDX tag has a validate attribute that you can use when converting WDDX to CFML or JavaScript. When you set this attribute to True, the XML parser uses the WDDX DTD to validate the WDDX data before deserializing it. If the WDDX is not valid, ColdFusion generates an error. By default, ColdFusion does not validate WDDX data before trying to convert it to ColdFusion or JavaScript data. The IsWDDX function returns True if a variable is a valid WDDX data packet. It returns False otherwise. You can use this function to validate WDDX packets before converting them to another format. For example, you can use it instead of the CFWDDX validate attribute so that invalid WDDX is handled within conditional logic instead of error-handling code. You can also use it to prevalidate data that will be deserialized by JavaScript at the browser. Using JavaScript ObjectsColdFusion provides two JavaScript objects, WddxSerializer and WddxRecordset, that you can use in JavaScript to convert data to WDDX. These objects are defined in the file webroot /cfide/scripts/wddx.js. The CFML Reference describes these objects and their methods in detail. Converting CFML Data to a JavaScript ObjectLet's create a simple example that takes a recordset generated from CFQUERY and uses WDDX to convert it to JavaScript that can be processed by our browser. Take a look at Listing 20.16. Listing 20.16 wddxtojs.cfm<cfquery datasource="icf" name="getUsers"> SELECT User.UserID, User.UserName, User.UserPassword, User.UserFirstName, User.UserLastName, User.UserEmail, User.UserStatus, User.UserLevelID FROM User </cfquery> <!--- Load the wddx.js file, which includes the dump function ---> <script type="text/javascript" src="/books/2/197/1/html/2//CFIDE/scripts/wddx.js"></script> <script> // Use WDDX to move from CFML data to JavaScript <cfwddx action="cfml2js" input="#getUsers#" topLevelVariable="qj"> // Dump the recordset to show that all the data has reached // the client successfully. document.write(qj.dump(true)); </script> Note To see how cfwddx Action="cfml2js" works, save this code under your webroot directory (for example, in wwwroot/myapps/wddxjavascript.cfm), run the page in your browser, and select View Source in your browser. Transferring Data from the Browser to the ServerIn this section, we are going to a create a more complex example that will demonstrate how you can use WDDX to exchange information between a web browser and the application server. In Listing 20.17, we serialize form field data, post it to the server, deserialize it, and then display the data. In reality, you can create very complex and sophisticated applications that exchange a large amount of data in this same way between the browser and the server using this same approach. Also note that our example uses the WddxSerializer JavaScript object to serialize the data and the cfwddx tag to deserialize the data. Listing 20.17 browsertoserver.cfm<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>Transferring Data from the Browser to the Server</title> <script language="JavaScript" type="text/javascript" src="/books/2/197/1/html/2//CFIDE/scripts/wddx.js"></script> <script language="JavaScript" type="text/javascript"> <!-- // Generic serialization to a form field function serializeData(data, formField) { if(document.personForm.firstName.value || document.personForm.lastName.value) doNext(); wddxSerializer = new WddxSerializer(); wddxPacket = wddxSerializer.serialize(data); if (wddxPacket != null) formField.value = wddxPacket; else alert('Couldn\'t serialize data'); } // Person info recordset with columns firstName and lastName // Make sure the case of field names is preserved var personInfo = new WddxRecordset(new Array('firstName', 'lastName'), true); // Add next record to end of personInfo recordset function doNext() { // Extract data var firstName = document.personForm.firstName.value; var lastName = document.personForm.lastName.value; // User must enter at least first name or last name. if(!firstName && !lastName) { alert('You must enter a first name and/or last name.'); return; } // Add names to recordset nRows = personInfo.getRowCount(); personInfo.firstName[nRows] = firstName; personInfo.lastName[nRows] = lastName; // Clear input fields document.personForm.firstName.value = ''; document.personForm.lastName.value = ''; // Show added names on list var newName = firstName + ' ' + lastName; newIndex = document.personForm.names.options.length; document.personForm.names.options.length = document.personForm.names.options.length + 1; document.personForm.names.options[newIndex].text = newName; document.personForm.names.options[newIndex].value = newName; } // --> </script> </head> <cfoutput> <!--- Data collection form ---> <form action="#cgi.script_name#" name="personForm" method="post"> <h1>Step 1.</h1> <p>Add as many names as you like.</p> <!--- Input fields ---> First name: <input type="text" name="firstName"><br> Last name: <input type="text" name="lastName"><br> <!--- button to add name to list ---> <input type="button" value="Next" onclick="doNext(); this.form.firstName.focus()"> <br><br> <h1>Step 2.</h1> <p>Serialize the names in to a WDDX Packet.</p> Names added so far:<br> <select name="names" size="5"> </select><br> <!--- button to serialize names in to wddx packet ---> <input type="button" value="Serialize" onclick="serializeData(personInfo, document.personForm.wddxPacket)"> <br><br> <h1>Step 3.</h1> <p>Send WDDX Packet to the server.</p> <!--- This is where the WDDX packet will be stored ---> <!--- In a real application this would be a hidden input field. ---> WDDX packet display:<br> <textarea name="wddxPacket" rows="10" cols="80" wrap="virtual"></textarea><br> <!--- button to submit wddx packet ---> <input type="submit" value="Submit"> </form> </cfoutput> <!--- Server-side processing ---> <hr> <strong>Server-side processing</strong> <br><br> <cfparam name="form.wddxPacket" default=""> <cfif Len(form.wddxPacket)> <cfif IsWDDX(form.wddxPacket)> <!--- Deserialize the WDDX data ---> <cfwddx action="wddx2cfml" input="#form.wddxPacket#" output="personInfo"> <!--- Display the query ---> The submitted personal information is:<br> <cfoutput query="personInfo"> Person #currentrow#: #firstName# #lastName#<br> </cfoutput> <cfelse> The client did not send a well-formed WDDX data packet! </cfif> </cfif> </body> </html> Storing Complex DataA major use of WDDX in ColdFusion is to store complex data. The simple example in Listing 20.18 uses WDDX to store complex data, a data structure that contains arrays as a string in a client variable. It uses the CFDUMP tag to display the contents of the structure before serialization and after deserializa-tion. It uses the HTMLEditFormat function in a CFOUTPUT tag to display the contents of the client variable. The HTMLEditFormat function is required to prevent the browser from trying to interpret (and throw away) the XML tags in the variable. Listing 20.18 wddxStruct.cfm<cfapplication name="relatives" clientmanagement="Yes"> <cfscript> Order = structNew(); Order.OrderID = 002; Order.OrderNum = 002; Order.OrderDate = "01/01/01"; Order.ShipDate = "01/28/01"; Order.ShipName = "Francis"; Order.ShipAddress = "128 Maine Street"; </cfscript> <br> <cfdump var="#Order#"><br> <br> <!--- Convert data structure to string form and save it in the client scope ---> <cfwddx action="cfml2wddx" input="#Order#" output="Client.wddxOrder"> The contents of the Client.Order variable:<br> <cfoutput>#HtmlEditFormat(Client.wddxOrder)#</cfoutput><br> <br> <!--- Now read the data from client scope into a new structure ---> <cfwddx action="wddx2cfml" input="#Client.wddxOrder#" output="OrderBack"> A dump of the wddxOrder structure <br> generated from client.wddxOrder<br> <br> <cfdump var="#OrderBack#"> As you can see, WDDX is probably the most simple and easy-to-use XML technology out there. Using WDDX, you can create simple content and data syndication applications, e-commerce systems, internal data-storage systems, and much more. You can even use WDDX along with web services as a payload. |