Recipe 20.13. Sending XML


Problem

You want to send XML data to a server-side script.

Solution

Create a URLRequest instance containing the XML data to send. Use flash.net.sendToURL( ) to send the data and ignore the server response, use flash.net.navigateToURL( ) to send the data and open the server response in a specific browser window, or use URLLoader.load( ) to both send the data and download the response into the .swf file.

Discussion

XML is normally used to transfer data to and from applications, and in this case, Flash movies. Therefore, it is quite unusual that you would want to create XML objects in your Flash movies for use within Flash alone. Instead, you generally load XML data from another source, create XML data in Flash for the purpose of sending to another application, or both.

This recipe examines sending XML data from Flash to another application, and there are lots of reasons to do this. For example, in a Flash game you might want to use XML to send the user's name and score to the server. At other times, you might want to send XML packets to a server-side script to invoke server-side functionality. This is a process that is sometimes called a remote procedure call (RPC), and it can use XML to send the function invocation information (function name, parameters, etc.) to the server. There is a formal specification for using XML in this manner called XML-RPC (see http://www.xmlrpc.com). So, as you can see, the possibilities for sending XML to the server are quite diverse.

As discussed in Recipe 20.11 and Chapter 19, ActionScript 3.0 consolidates sending and loading data into the methods of the flash.net package. Previously, the XML class contained both send( ) and sendAndLoad( ) methods to send XML to a server, but in ActionScript 3.0 you must use URLRequest instead. Recipes 19.6 and 19.7 cover the basic techniques using a URLReuest instance to send and receive data.

Let's take a look at a complete working example. In what follows, you'll first create the necessary client-side ActionScript code, and then you should choose from one of the server-side solutions. Choose one that's supported by your server (or your personal computer, if you use that as your server). There are server-side scripts in Perl, PHP, and ColdFusion.

The first thing you should do is create a new ActionScript 3.0 class with the following code:

package {   import flash.display.*;   import flash.text.*;   import flash.filters.*;   import flash.events.*;   import flash.net.*;   public class XMLSendLoadExample extends Sprite {          private var _message:TextField;     private var _username:TextField;     private var _save:SimpleButton;              public function XMLSendLoadExample(  ) {       initializeDispaly(  );       }          private function initializeDispaly(  ):void {       _message = new TextField(  );       _message.autoSize = TextFieldAutoSize.LEFT;       _message.x = 10;       _message.y = 10;       _message.text = "Enter a user name";              _username = new TextField(  );       _username.width = 100;       _username.height = 18;       _username.x = 10;       _username.y = 30;       _username.type = TextFieldType.INPUT;       _username.border = true;       _username.background = true;              _save = new SimpleButton(  );       _save.upState = createSaveButtonState( 0xFFCC33 );       _save.overState = createSaveButtonState( 0xFFFFFF );       _save.downState = createSaveButtonState( 0xCCCCCC );       _save.hitTestState = save.upState;       _save.x = 10;       _save.y = 50;       // When the save button is clicked, call the handleSave method       _save.addEventListener( MouseEvent.CLICK, handleSave );              addChild( _message );       addChild( _username );       addChild( _save );     }          // Creates a button state with a specific background color     private function createSaveButtonState( color:uint ):Sprite {       var state:Sprite = new Sprite(  );              var label:TextField = new TextField(  );       label.text = "Save";       label.x = 2;       label.height = 18;       label.width = 30;       var background:Shape = new Shape(  );       background.graphics.beginFill( color );       background.graphics.lineStyle( 1, 0x000000 );       background.graphics.drawRoundRect( 0, 0, 32, 18, 9 );       background.filters = [ new DropShadowFilter( 1 ) ];                  state.addChild( background );       state.addChild( label );       return state;     }          private function handleSave( event:MouseEvent ):void {       // Generate a random score to save with the username       var score:int = Math.floor( Math.random(  ) * 10 );              // Create a new XML instance containing the data to be saved       var dataToSave:XML = <gamescore>                              <username>{username.text}</username>                              <score>{score}</score>                            </gamescore>;              // Point the request to the script that will handle the XML       var request:URLRequest = new URLRequest( "/gamescores.cfm" );       // Set the data property to the dataToSave XML instance to send the XML       // data to the server       request.data = dataToSave;       // Set the contentType to signal XML data being sent       request.contentType = "text/xml";       // Use the post method to send the data       request.method = URLRequestMethod.POST;              // Create a URLLoader to handle sending and loading of the XML data       var loader:URLLoader = new URLLoader(  );       // When the server response is finished downloading, invoke handleResponse       loader.addEventListener( Event.COMPLETE, handleResponse );       // Finally, send off the XML data to the URL       loader.load( request );     }          private function handleResponse( event:Event ):void {       try {         // Attempt to convert the server's response into XML         var success:XML = new XML( event.target.data );                  // Inspect the value of the success element node         if ( success.toString(  ) == "1" ) {           _message.text = "Saved successfully.";             } else {           _message.text = "Error encountered while saving.";         }                } catch ( e:TypeError ) {         // Display an error message since the server response was not understood         _message.text = "Could not parse XML response from server.";       }     }   } }

The contentType property of a URLRequest instance is set to application/x-www-form-urlencoded by default, so it's important to set contentType to text/xml whenever you want to send XML data. Additionally, you'll want to set the method of the request to URLRequestMethod.POST to send the XML data to the server via HTTP POST.

Obviously, in a real-world example, the user's score would be generated by her performance in a game. In this example, we just want to demonstrate sending and receiving XML, so we generate the score randomly.


The next step is to create the server-side script. First, here's the Perl option. If you use this option, place the following code in a text file named gamescores.cgi (or gamescores.pl) in a directory on your web server that has CGI access enabled (usually cgi or cgi-bin).

#!/usr/bin/perl       # Flash/Perl+CGI XML interaction demo # Arun Bhalla (arun@groogroo.com)       use strict; use XML::Simple; use CGI;       my $ScoreFile = "scores.txt";       # Here we assume that this CGI script is receiving XML in text/xml  # form via POST. Because of this, the XML appears to the script  # via STDIN. my $input = XMLin(join('',<STDIN>));        # Write out the HTTP header print CGI::header('text/xml');       # Try to open score file for writing, or return an error message. open(SCORES, ">> $ScoreFile") || (printMessage(0) &&                    die "Error opening $ScoreFile");       # Save the score in a pipe-delimited text file. print SCORES join('|', $input->{username}, $input->{score}), "\n";       # Return the result in XML. printMessage(1);       # Subroutine to output the result in XML. sub printMessage {   my $value = shift;   my $message = {};   $message->{success} = $value;   print XMLout($message, keeproot => 1, rootname => 'success'); }

If you are using ColdFusion, a sample ColdFusion script is provided in the following code block. Place this code in a ColdFusion page named gamescores.cfm within a directory on your web server that can run ColdFusion pages:

<cfsilent> <cfsetting enablecfoutputonly="Yes"> <cfset success = 0> <cftry>   <!--- XML packet sent by Flash. --->   <cfset scores_xml = XmlParse( getHTTPRequestData(  ).content ) >     <!--- Parse out the XML packet sent from Flash. --->     <!--- Grab the username and score from the XML document and save as           local variables so they are easier to work with. // --->   <cfset username = scores_xml.gamescore.username.XmlText >   <cfset score = scores_xml.gamescore.score.XmlText >     <!--- Append the latest score to our scores file. This could also be           stored in the database or another XML document. // --->   <cffile action="APPEND" file="#ExpandPath( 'scores.txt' )#"   output="#username#|#score#|#getHTTPRequestData(  ).content#" addnewline="Yes">   <cfset success = 1 >   <cfcatch type="Any">     <cfset success = 0 >     <cffile action="APPEND" file="#ExpandPath( 'attempts.txt' )#" output="ERROR"      addnewline="Yes">   </cfcatch> </cftry> </cfsilent> <cfcontent type="text/xml"> <cfoutput><?xml version="1.0" ?><success>#success#</success></cfoutput> <cfsetting showdebugoutput="no" enablecfoutputonly="No">

If you are using PHP on your server, place the following code in a PHP page named gamescores.php on your web server in a directory that allows PHP access:

<?php       // Read In XML from Raw Post Data. $xml = $GLOBALS['HTTP_RAW_POST_DATA'];       // Process XML using DOM PHP extension. $document = xmldoc($xml);       // Read root element <gameinfo>. $rootElement = $document->root(  );       // Read child nodes <username> and <score>. $childNodes = $rootElement->children(  );       $data = "";       // Loop through child nodes and place in array. foreach($childNodes as $childNode){   // Add data to array;   $name = $childNode->tagName(  );   $value = $childNode->get_content(  );   $data[$name] = $value; }       // Append data to scores.txt ( format: username|score ) $fp = fopen("scores.txt","a+"); $dataString = $data['username'] . "|" . $data['score'] . "\n"; fputs($fp,$dataString,strlen($dataString)); fclose($fp);       // Return success code to Flash echo "<success>1</success>"; ?>

All three scripts have one thing in common: they all output an XML response with <success> as the root node, containing a text node value of 1 for successful save and 0, which indicates some type of error.

To test the Flash movie once you have it and the server-side script in place, you need only to run the movie and click on the button. The movie should get a successful response, and if you check in the directory on the server in which the script has been created, you should find a scores.txt file containing the data that was entered via the Flash movie.

See Also

Chapter 19specifically Recipes 19.6 and 19.7, and Recipe 20.11.




ActionScript 3. 0 Cookbook
ActionScript 3.0 Cookbook: Solutions for Flash Platform and Flex Application Developers
ISBN: 0596526954
EAN: 2147483647
Year: 2007
Pages: 351

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net