Text content in XML
One of the more frequently asked questions regarding XML in Flash is related to the text content of XML nodes. Consider the following XML:
[xml]
<people>
<person>
<givenName>Timothy</givenName>
<initial>J</initial>
<surName>Walters</surName>
</person>
</people>
[/xml]
To access the text in this XML, you will often see something like the following ActionScript:
[as]
// ... once XML has been loaded and parsed into xmlPeople:
// get reference to the person we want
xmlPerson = xmlPeople.firstChild.firstChild;
// assign text to our text boxes
txtGivenName.text = xmlPerson.childNodes[0].firstChild.nodeValue;
txtInitial.text = xmlPerson.childNodes[1].firstChild.nodeValue;
txtSurName.text = xmlPerson.childNodes[2].firstChild.nodeValue;
[/as]
NOTE: the above only works if you have used the "ignoreWhite" property with a value of true!
People often ask why they have to use ".firstChild.nodeValue", why can't they just use ".nodeValue" on the <givenName> node?
To answer this, first consider the following XML:
[xml]
<comments>
<comment>
<b>Tim says: </b>That's <i>interesting</i>...
</comment>
</comments>
[/xml]
Although I wouldn't recommend using XML like that, it's entirely valid. It's referred to as "Mixed Content", where you've got XML tags (in this case the HTML <b> tag and <i> tag) mixed in with your text. It's most commonly used when you allow HTML in your data (although this too is something that must be done carefully, as the HTML has to be valid XML, but that's another topic).
The XML document has one child, the "<comments>" element. This element has one child, the "<comment>" element. This element has 4 child elements (or 5 if ignoreWhite isn't set to true). It's children are an element named "b" (which has a child node of type text), a text node (nodeType = 3), an element named "i" (which has a child node of type text), and another text node.
Lets draw a tree:
[tree]
node: name="comments", type=1
node: name="comment", type=1
node: name="b", type=1
node: name=(null), type=3, value="Tim says: "
node: name=(null), type=3, value="That's "
node: name="i", type=1
node: name=(null), type=3, value="interesting"
node: name=(null), type=3, value="..."
[/tree]
In case you haven't worked it out yet, something that allowed you to get the text of the <comment> tag would return the string "That's ..." (it would take the two children and normalize them into a single string). You would lose the structure (and meaning) of your XML. Thus text is always created as a node of type text (nodeType=3) in the object heirarchy. This only seems odd when you have a single text node inside your element (like the first example).
To make life easier, I've written some extensions to the Flash MX XML object. One such extension is the ".innerText" method.
For those cases where you only want the text, you can use the ".innerText" method. If you examine the source you might notice that it actually checks all children and combines the innerText & nodeValue properties.
[as]
XMLNode.prototype.innerText = function()
{
var strText = "";
var xmlNode;
for( var i=0; i<this.childNodes.length; i++ )
{
xmlNode = this.childNodes[i];
switch(xmlNode.nodeType)
{
case 1: // elements
strText += xmlNode.innerText();
break;
case 3: // text
strText += xmlNode.nodeValue;
break;
default: // comments etc
break;
}
}
return strText;
};
[/as]