Friday, April 3, 2009

Escaped Newline not properly rendering from XML

When setting a Flash TextField's text to some data that is loaded from an external XML file, I noticed the newline characters defined in my XML file, "\n", were being rendered as the string "\n" rather than an actual line-break.

The Problem

Here is a simplified example of this situation:

The XML file
<root test="Line1\nLine2\nLine3"></root>

The ActionScript
var xml:XML = new XML();

xml.load("slash-n.xml");

xml.onLoad = function()
{
   var testAttr:String = this.firstChild.attributes.test;

   trace(testAttr);
   //this traces: Line1\nLine2\nLine3

   trace("Line1\nLine2\nLine3");
   //this traces:
   //Line1
   //Line2
   //Line3

   trace(testAttr.indexOf("\\n"));
   //this traces: 5
};

This example illustrates that the first trace, using the externally-loaded string, actually outputs "\n", whereas the second trace renders the newline characters in the string literal as line-breaks.

The problem here is that the XML class actually escapes slashes it sees by doubling them up, as in "\\n". This behavior is observed in the third trace which shows that "\\n" exists in the string.

The Solution

There are two ways to solve this -- a quick way and a better way.

A Quick Solution - ActionScript Change
The quick way to solve this, leaving the XML as-is, is to simply replace "\\n" with "\n" after the XML load:

ActionScript now replaces "\\n" with "\n"
var xml:XML = new XML();

xml.load("slash-n.xml");

xml.onLoad = function()
{
   var testAttr:String = this.firstChild.attributes.test;

   testAttr = testAttr.split("\\n").join("\n");

   trace(testAttr);
   //this now traces:
   //Line1
   //Line2
   //Line3

};

This solves the problem.

But what if our attribute needs to contain other special characters such as a less-than/greater-than signs or double-quotes? Those must be escaped using the entities &lt; &gt and &quot;, and with a lot of those in the XML, this hinders readability and, if the file is being managed by hand, also hinders writability. A better way would be to use a XML CDATA block instead of an XML attribute.

A Better Solution - ActionScript and XML Changes
This solution takes advantage of the CDATA block, whose contents are not parsed during the XML load, thus not requiring us to escape less-than/greater-than signs and double-quotes.

The ActionScript XML class still doubles-up slashes so we will still need to replace "\\n" with "\n", but our XML file will have higher readability and writability.

Before: XML attribute leads to low readability/writability
<root test="&quot;Line1&quot;\n&gt;&gt;Line2\n&lt;Line3&gt;"></root>

After: XML changed for higher readability/writability
<root><![CDATA["Line1"\n>>Line2\n<Line3>]]></root>

ActionScript refers to CDATA block and replaces "\\n"
var xml:XML = new XML();

xml.load("slash-n.xml");

xml.onLoad = function()
{
   var testCdataText:String = this.firstChild.firstChild.nodeValue;

   testCdataText = testCdataText.split("\\n").join("\n");

   trace(testCdataText);
   //this traces:
   //"Line1"
   //>>Line2
   //<Line3>

};

This solves the newline problem while also increasing the readability and writability of the XML.

No comments:

Post a Comment

Was this post helpful? Do you have questions about it? Do you want to share your own programming blog? I'd love to read your feedback.

Note: Only a member of this blog may post a comment.