Hack 85 Import ASC Files as XML 
XML class for basic file loading. Then parse
the text out of the single resulting XML node.
XML is a well-known format for sending and
receiving data to and from the Flash Player. When you want to load a
smaller amount of data (or unstructured data), the
LoadVars class is another popular route. XML is
common in web design and web-related technologies but many non-web
applications use proprietary data formats not supported by the Flash
Player. Two common options for loading nonstandard data into Flash
are to convert the data into XML or ampersand-delimited text files
(for LoadVars). Both approaches force you to
reformat the data every time you update the source data, making for
an inefficient workflow and possibly introducing errors during
conversion.
A better route is to import the source application's
original file format if possible. Here we import the ASC file format,
which is common to many applications.
ASC Files
The ASC file
format consists of any sequential ASCII file structured as a series
of lines of space-delimited data, each line being terminated with a
carriage return (or other delimiter), such as:
data data data data data<CR>
data data data data data<CR>
...
data data data data data<CR>
ASC files and ASC-style files are typically used as a general file
format that is easy to read by other applications. Many 3D
applications support plug-ins that allow them to import and export
ASC files, although fewer have this native capability.
ASC files are easy to hand-edit in any text editor because:
The data file is simple ASCII. The data does not contain any nonprintable characters or escape
sequences (a.k.a. control codes). The data is ordered in a regular table format that is easy for humans
to read.
This format should not be confused with the Flash-specific ASC
(ActionScript Communications) file format used by Flash Communication
Server MX.
This hack uses an ASC file created by 3D Studio Max. As you can see,
it is essentially a table of data:
Ambient light color: Red= 0.0 Green= 0.0 Blue= 0.0
Named object: "Torus01"
Tri-mesh, Vertices: 100 Faces: 200
Vertex list:
Vertex 0: X:-0.4 Y: 0.0 Z:61.1
Vertex 1: X:-0.4 Y:-11.8 Z:57.3
...
Vertex 98: X:-27.5 Y:19.0 Z:38.5
Vertex 99: X:-33.4 Y:11.8 Z:46.6
Face list:
Face 0: A:0 B:11 C:10 AB:0 BC:1 CA:1
Smoothing: 1
Face 1: A:0 B:1 C:11 AB:1 BC:1 CA:0
Smoothing: 1
...
Face 198: A:99 B:0 C:9 AB:0 BC:1 CA:1
Smoothing: 1
Face 199: A:99 B:90 C:0 AB:1 BC:1 CA:0
Smoothing: 1
The data forms a 3D torus (doughnut), as seen in Figure 10-12.

The problem is how to load our ASC file into Flash. One of the
easiest (and downright sneaky) ways is to trick Flash into thinking
the file is an XML file. The fact that the file
isn't really XML causes Flash to assume that the
file contains only one node. This single node is a string containing
the entire contents of the file, which we can parse using standard
string-handling (rather than XML node-parsing) functions.
Import and Parse the ASC File
The functions
handleIncoming( ) and readXMLstart(
) in the following listing cause Flash to load the ASC
file as an XML file and place the contents of the file into a string,
my3dFile, if the load is successful.
We know that each line of the ASC file contains related data and ends
with a carriage return ("\n" or
Key.ENTER in Flash). To split the ASC file into
separate lines of data, we simply search through the file looking for
each occurrence of "\n" (we
don't use String.split( )
because we want to loop through the array anyway to look for the data
of interest, as discussed later). The readASC( )
function separates the ASC file into lines and stores them in an
array named shape:
handleIncoming = function (success) {
if (success) {
readXMLstart( );
}
};
readXMLstart = function ( ) {
my3dFile = xObj.firstChild.nodeValue;
readASC( );
};
readASC = function ( ) {
var oIndex:Number = 0;
var rIndex:Number = 0;
var elem:String = "";
while (rIndex != -1) {
rIndex = my3dFile.indexOf("\n", oIndex);
elem = my3dFile.substring(oIndex, rIndex);
// Skip any lines that are padding (less than 30 characters)
if (elem.length > 30) {
shape[shape.length] = elem;
}
oIndex = rIndex+1;
}
};
var xObj:XML = new XML( );
var my3dFile:String = new String( );
var shape:Array = new Array( );
xObj.onLoad = handleIncoming;
xObj.load("torus.asc");
The String.substring( ) method searches
my3dFile and extracts the characters between the
start of the first unsearched character position,
oIndex ("old
index"), and the position of the next
"\n", rIndex
("return index"), as a line of
data:
rIndex = my3dFile.indexOf("\n", oIndex);
elem = my3dFile.substring(oIndex, rIndex);
The value of rIndex is found by looking for the
next "\n" via the
String.indexOf( ) method. The code knows when
the end of the ASC file is reached because String.indexOf(
) returns -1 when the search string cannot be found.
Some lines of the ASC file are not of interest to us (i.e., they
contain data other than the raw point and line data we are looking
for), and we can get rid of these by checking for some identifying
characteristic before we treat the current line as valid. In our
case, if the line length is greater than 30 characters, the currently
found line is assumed to be valid data and stored as the next element
in array shape:
if (elem.length > 30) {
shape[shape.length] = elem;
}
Figure 10-13 shows the first 10 elements of the
shape array as created by the code presented.
We'll filter out anything that
isn't vertex data momentarily.

Parse Each Line in an ASC File
Normally, we don't want
to store the individual lines but rather the relevant data contained
within them. Given that the ASC file in question represents a 3D
shape, we want to extract the vertex point data (x, y, z) of this
shape.
A typical data line that contains 3D point data in our imported file
looks like:
Vertex 98: X:-27.5 Y:19.0 Z:38.5
From this line, we can deduce that:
All lines that contain vertex data in the ASC file are at least 30
characters long and start with
"Vertex." Within these lines, the x data is preceded by
"X:" (similarly for the y and z
data).
We can add these rules to the code as follows. We can determine
whether the current line contains vertex data by looking for a
"V" as the first character of the
current line:
if (elem.substring(0, 1) == "V") {
If this is the case, we search through the line for the offset of
"X:",
"Y:", and
"Z:":
posX = elem.indexOf("X:", 0);
posY = elem.indexOf("Y:", posX);
posZ = elem.indexOf("Z:", posY);
These offsets are the same for all lines starting with
"Vertex" in the example file, but
that is not guaranteed, so we have to search for the start positions
rather than assuming them.
We use these offsets to extract the x, y, and z coordinates. We add 2
to the starting offset to account for the letter and colon, such as
"X:".
pX = Number(elem.slice(posX + 2, posX + 6));
pY = Number(elem.slice(posY + 2, posY + 6));
pZ = Number(elem.slice(posZ + 2, posZ + 6));
Finally, we can add the (x, y, z) point as structured Flash data that
can be used by ActionScript to build the 3D shape [Hack #37] . Here, I add the 3D point
data as properties to the shape array, as shown in
Figure 10-14.

shape[sPointer] = new Object( );
shape[sPointer].x = pX;
shape[sPointer].y = pY;
shape[sPointer].z = pZ;
The full code to extract the (x, y, z) point data from our 3D Studio
Max ASC file is:
handleIncoming = function (success) {
if (success) {
readXMLstart( );
}
};
readXMLstart = function ( ) {
my3dFile = xObj.firstChild.nodeValue;
readASC( );
};
readASC = function ( ) {
var oIndex:Number = 0;
var rIndex:Number = 0;
var elem:String = "";
var posX:Number = 0;
var posY:Number = 0;
var posZ:Number = 0;
while (rIndex != -1) {
rIndex = my3dFile.indexOf("\n", oIndex);
elem = my3dFile.substring(oIndex, rIndex);
if (elem.length > 30) {
if (elem.substring(0, 1) == "V") {
posX = elem.indexOf("X:", 0);
posY = elem.indexOf("Y:", posX);
posZ = elem.indexOf("Z:", posY);
pX = Number(elem.slice(posX + 2, posX + 6));
pY = Number(elem.slice(posY + 2, posY + 6));
pZ = Number(elem.slice(posZ + 2, posZ + 6));
shape[sPointer] = new Object( );
shape[sPointer].x = pX;
shape[sPointer].y = pY;
shape[sPointer].z = pZ;
sPointer++;
}
}
oIndex = rIndex+1;
}
};
var xObj:XML = new XML( );
var my3dFile:String = new String( );
var shape:Array = new Array( );
var sPointer:Number = 0;
xObj.onLoad = handleIncoming;
xObj.load("torus.asc");
You can see Edwin Heijmen's version of this file in
the Experiments section at http://www.poeticterror.com. The full version
uses the 3D point data to create an interactive 3D wireframe viewer,
as shown in Figure 10-15.

Final Thoughts
As Flash becomes more of a general web multimedia platform, you are
increasingly likely to want to import data into a SWF from
nonstandard or non-web-based applications. Even if this data is not
XML, you can use the XML class to load the data
(Flash doesn't care whether a file you ask it to
treat as XML is actually XML). This is one of the better ways to
import structured text files that are formatted in a way that Flash
does not understand, because you gain many of the features of the
XML class, such as notification via the
onLoad event that the file is loaded.
Furthermore, the raw ASC file format makes it particularly easy to
import data not intended for Flash (such as 3D point data or database
recordsets) into a running SWF, so there may be little gain in
converting to native Flash formats such as XML.
Avoid the temptation to always convert data into XML. Doing so
unnecessarily adds steps to the production workflow if the source
application updates the data, however infrequently.
—Edwin Heijmen
|