This is an archived tutorial from the kirupa.com legacy collection. It covers software that may no longer be available, but it is kept online because the ideas still hold up.
Even knowing all you need to know or all you should know doesn't mean you won't find yourself caught up in a jam without knowing why things aren't working the way they're supposed to. This section will point out some of those specific issues (that haven't been addressed earlier) and what can be done to resolve them.
Though its possible the reference is not correct (something you should tripple check) this problem is usually associated with XML loaded into an XML instance whose ignoreWhite property was not set to true. When ignoreWhite is... ignored, its default is used with is false. This means all white space between adjacent elements are treated as text nodes throwing off your nodes count and disrupting the order of where you think everything should be. Set ignoreWhite to true and you should be golden.
This is probably the biggest issue out there for people using XML in ActionScript 2.0 classes. This doesn't necessarily revolve around XML so much, but rather about dealing with callback event handlers like onLoad from within classes.
The problem is that if you define an onLoad event from within a class method, the onLoad script cannot access class properties. Example
class XMLContentLoader {
public var target_txt:TextField;
private var _xml:XML;
function XMLContentLoader(url:String, target:TextField){
target_txt = target;
_xml = new XML();
_xml.ignoreWhite = true;
_xml.onLoad = function(success){
if (success) target_txt.text = this.firstChild.toString();
}
_xml.load(url);
}
}
Here, the XMLContentLoader class creates instances that loads XML from a URL string and displays its firstChild (the full XML document) into a textfield saved under the target_txt property. Problem is, the onLoad can't correctly reference the target_txt property. WHY, sweet child of mine WHY!?!
The reason for this is because once you've entered that onLoad method, you are no longer in the scope of the class instance. You have now entered the scope of the XML instance. Within this scope, when attempting to access target_txt, you are attempting to access target_txt within the XML instance and not the XMLContentLoader instance. Thankfully, there are a couple of ways around this.
1. Use a local variable. If you created the event handler (onLoad) function within a class method, then that function has access to all local variables declared within that method in which its defined. If you assign the needed property reference to a local variable in that host method, it will carry into the scope of the scope of the handler giving you a valid reference.
var txt = target_txt;
_xml.onLoad = function(success){
if (success) txt.text = this.firstChild.toString();
}
For variable reference only; not safe for calling class methods.
2. Define the variable within the object receiving the handler. Since when in the onLoad the _xml instance is looking for its own target_txt and not the class instance's, what you could do is just copy that variable, keeping the same name, within the _xml instance. Then, the onLoad would correctly resolve that variable when it is referenced. Now, the flip side to this in AS 2.0 is that, at least with the XML object, that you're dealing with instances of a non-dynamic class. This means that you cannot, technically, add or access properties or methods that are not defined within its class definition. You can, however, trick Flash's compiler to ignore this by using associative array syntax to define your property, in this case, target_txt.
_xml["target_txt"] = target_txt;
_xml.onLoad = function(success){
if (success) target_txt.text = this.firstChild.toString();
}
Using _xml["target_txt"] tricks the compiler as when using [] to access variables. The compiler can't be certain of what value is within the brackets (it could be a variable that could be valid or invalid) so it ignores the reference altogether letting you get by with compiler deceiving heathenry. When in the onLoad, target_txt is correctly found because it is defined within the _xml instance. To add injury to insult, the compiler isn't smart enough to understand this change in scope either (actual running ActionScript knows the change, just not the compiler creating the SWF) so as you attempt to access target_txt in the onLoad function without [], the compiler won't complain as it still assumes that when you're using you're in the scope of the class where target_txt is a valid property.
For variable reference only; not safe for calling class methods.
3. Define a reference to the class instance within the object receiving the handler. This approach is a little like the previous only this one adds a reference to the class instance itself and not just one property. This is helpful if you're dealing with many variables or you need to pass the class instance itself in to function calls within the handler function's scope etc. Here, again, the compiler gets in the way when dealing with non-dynamic XML instances. There's an added complication, though, as when using a reference in this manner, you're not duplicating an existing class property so the compiler will know it doesn't exist where ever you use it. Thankfully, the compiler did learn one thing in its limited schooling, and that was that this-referenced properties within non-class function definitions should go ignored. So, within the onLoad, a class reference variable can be left alone by the compiler if this is used to specify that the property does in fact belong to the object in which the handler is being defined (of course this is a little contradictory to some of its other behavior, but what are you going to do). The initial class reference when defined within the XML instance will still need [] to be ignored by the compiler, however.
_xml["hostInstance"] = this;
_xml.onLoad = function(success){
if (success) this.hostInstance.target_txt.text = this.firstChild.toString();
}
Note: you could also create an undefined Object property in the class called hostInstance to prevent the need to use this. Also, if you're confident in your coding, you could also just drop the typing altogether for the XML instance preventing any of the compiler complications mentioned above.
private var _xml;
3.1. Combine 3 and 1. Use a local variable to reference the class instance. This takes away the need to a) define any extra variables within the object getting the event handler b) trick the compiler and c) define multiple variables for what ever properties you wish to reference
var host = this;
_xml.onLoad = function(success){
if (success) host.target_txt.text = this.firstChild.toString();
}
4. Use the Delegate Utility. Available as of Flash MX 2004 7.2, this is probably the most "official", though possibly also the most confusing (and less apparent) method. Delegate is a class in mx.utils available to ActionScript 2.0 that allows you to change the scope of a function call from one object to another. Basically its a wrapper for the functionality that function.call() and function.apply() provide. Delegate just makes it a little easier to intercept function definitions in one object which are to be executed within the scope of another. Here's a simple example of its use.
import mx.utils.Delegate;
var objectA:Object = {name: "object A"};
var objectB:Object = {name: "object B"};
function getName():String {
return this.name;
}
objectB.getName = Delegate.create(objectA, getName);
trace( objectB.getName() ); // traces "object A";
Here, the static method create is used off of the Delegate class to create a function (getName) that is assigned to object B but, when run, is run in the scope of object A. This means that any instance of 'this' in that function will refer to object A instead of object B even though it is being called from object B.
This can then be applied to the XML example were we could have the onLoad be run in the scope of the class thereby making all references to class properties valid as the call would be within the scope of the class instance and not the XML object. For the sake of simplicity, we'll make the function to be used in the onLoad a method of the class. This is not uncommon to do anyway. Here, it makes the assignment using Delegate.create() a lot easier. Here is the full modified class:
import mx.utils.Delegate;
class XMLContentLoader {
public var target_txt:TextField;
private var _xml:XML;
function XMLContentLoader(url:String, target:TextField){
target_txt = target;
_xml = new XML();
_xml.ignoreWhite = true;
_xml.onLoad = Delegate.create(this, onLoadEvent);
_xml.load(url);
}
function onLoadEvent(success:Boolean):Void {
if (success) target_txt.text = _xml.firstChild.toString();
}
}
First, in order to use Delegate, at least by its short name, import is used to bring it in from mx.utils.Delegate (otherwise, you'd have to run it as mx.utils.Delegate.create()). That happens above the class definition before anything else. Then, in the constructor you can see it being used in defining the onLoad event for the _xml XML instance. It takes two arguments, an object and a function. The object is the object in which the function is going to be run. Since we want the onLoad to run within the scope of the class, this is passed in (representing the class instance) as the object. The function is the class's own onLoadEvent function defined below. It now, when run, will correctly reference target_txt as a property of the class without any trouble. Of course, you can also see that because the scope of the onLoad method is no longer within the XML instance and this represents the class, _xml has to be used in order to access content of the XML instance and what had been loaded.
Note: If you use a method for your onLoad event that is defined as a method within the class like the onLoadEvent method above, then options 1 and 3.1 which use local variables, would not be a valid solution for the scoping problem.
If you're trying to load XML across domains, i.e. trying to have a SWF on your site load an XML document from another site, you're XML may not make it because of security restrictions first implemented in Flash Player 6. To see how to get around this, read a technote available from Colin Moock's web site.
In using ignoreWhite, Flash physically removes the extraneous white space between nodes from the XML document as its brought into Flash often ruining your formatting. If that XML is then sent back to the server, the white space remains removed and what you get is a long line of elements and text nodes that seem all to blend together.
Similarly, Flash converts CDATA sections in XML to simple text nodes within an XML instance. Flash reads CDATA fine when loaded but, like with the white space, in sending off the XML to the server, that CDATA is no longer CDATA and is instead a converted text node.
When Flash removes all your white space and converts CDATA to text nodes, you've just lost that readability. This is especially annoying when using other markup like HTML and more so when you want to look at that XML in some other context other than within Flash. After all, part of the advantage of having XML is that it's readable. What's more readable to you in the following examples?
<?xml version="1.0"?>
<gallery>
<title>Image Gallery A</title>
<author>senocular</author>
<page date="01/04/2005" name="photo05.html">
<![CDATA[<html>
<head>
<title>Photo #05</title>
</head>
<body>
<div align="center">
<p><b>Photograph 05 of 50</b></p>
<img src="images/photo05.jpg" alt="Photo #05" />
</div>
</body>
</html>]]>
</page>
<comments>Please add the date of posting.</comments>
</gallery>
or
<?xml version="1.0"?>
<gallery><title>Image Gallery A</title><author>senocular</author><page date="01/04/2005" name="photo05.html">
<![CDATA[<html>
<head>
<title>Photo #05</title>
</head>
<body>
<div align="center">
<p><b>Photograph 05 of 50</b></p>
<img src="images/photo05.jpg" alt="Photo #05" />
</div>
</body>
</html>]]>
</page><comments>Please add the date of posting.</comments></gallery>
You can get around this using the previously mentioned format function. The format function, in its original design, is used to create a multi-lined, indented string representation of XML despite it having been formatted otherwise (say, as a result of using ignoreWhite). Using this to generate XML that is to be sent to the server pretty much solves the ignoreWhite problem right there. You would most likely have to use a loadVars object to send the string, but that's not really a problem.
The CDATA still remains. But, similarly, this too can be solved using format. What format does is re-writes XML node for node so that it can be relayed in an alternative format, namely, a readable one. A small modification to this, and some manual editing of your XML instance, can make it so that format correctly converts text nodes back into CDATA sections.
Because all CDATA sections are initially converted into text nodes, there's no real way to identify a real text node from a previously defined-as-CDATA node. This is why the manual editing previously mentioned is required. Basically you'd just have to go through the XML and manually mark specific text nodes as being CDATA so that when format runs through all the nodes, it can check for this mark and appropriately change all the appropriate text nodes into CDATA. Here is the rewrite of format with the alteration in bold:
XMLNode.prototype.format = function(indent){
if (indent == undefined) indent = "";
var str = "";
var currNode = this.firstChild;
do{
if (currNode.hasChildNodes()){
str += indent + currNode.cloneNode(0).toString().slice(0,-2) + ">\n";
str += currNode.format(indent+"\t");
str += indent + "</" + currNode.nodeName + ">\n";
}else{
if (currNode.isCDATA) str += indent + "<![CDATA[" + currNode.nodeValue + "]]>\n";
else str += indent + currNode.toString() + "\n";
}
}while (currNode = currNode.nextSibling);
return str;
}
An additional if statement is added that checks for an isCDATA property within the current node in the iteration. If the value is true then a CDATA section is created using the node's nodeValue instead of it's toString() representation which gets rid of all the character entity references and uses the actual node's value which, being within the CDATA tag is acceptable.
Now its just a matter of going through and defining a true isCDATA property to all the text nodes you wish to formatted as CDATA sections.
my_xml.firstChild.firstChild.isCDATA = true;
When text is brought into Flash and displayed in a text field, whitespace from that text is retained allowing you to mainttain tabbing and line breaks. Depending on your operating system, line breaks may consist of one of the following:
| Character | Represents | OS |
| \r | carriage return | Mac OS <= 9 |
| \n | newline | Unix (OSX) |
| \r\n | (both) | Windows |
Flash understands both \r and \n as line breaks. The problem comes with Windows line breaks which actually uses both \r and \n to represent one single line break. When this is brought into Flash, that single line break is interpreted as two.
To solve this problem, you can either replace all instances of either \r or \n from within Flash before the text is added to a text field or you can simply remove it beforehand (prefered) using a more advanced text editor - something other than notepad - which will let you distinguish between characters used for line breaks.
So the Flash XML methods send and sendAndLoad send your XML to a URL as raw Post data. The variable commonly used to access this post data in PHP is:
$HTTP_RAW_POST_DATA
Sometimes this doesn't always work (or your version of PHP may not support it). If you're having problems using $HTTP_RAW_POST_DATA, try instead using
file_get_contents("php://input");
php://input represents the standard input stream of the PHP file. Not only does the above solution use less memory than $HTTP_RAW_POST_DATA, but it also does not require any special php.ini directives to function properly (which may be causing you problems with $HTTP_RAW_POST_DATA in the first place). For versions of PHP >= 4.3.0.
That wraps up this tutorial. A huge thank you to all of you who buy kirupa's books, became a paid subscriber, watch the videos, and/or interact on the forums. Your support is what keeps writing like this online! 😇
This tutorial was written by senocular, also known as Trevor McCauley. He has been one of this community's most generous teachers since the early Flash days, and he is still around: find him on senocular.com and on the forums.
:: Copyright KIRUPA 2026 //--