E4X Add CDATA content
Asked Answered
C

6

11

Basically I need to define a node name and its CDATA content using variables.

var nodeName:String = "tag";
var nodeValue:String = "<non-escaped-content>";

Naively I thought this would work :

var xml:XML = <doc><{nodeName}><![CDATA[{nodeValue}]]></{nodeName}>

Outputs :

<doc><tag><![CDATA[{nodeValue}]]></tag></doc>

In a previous version of the script designed for FP9 I bypassed the problem by using :

new XMLNode( XMLNodeType.XMLNodeType.CDATA_NODE, nodeValue ); // ...

but this doesn't seem to work in FP10, and I have the feeling the method is somehow depreciated anyway.

Anyone an elegant solution for this ?

Cytology answered 6/8, 2009 at 14:57 Comment(0)
F
7

how about this:

var xml:XML = <doc><{nodeName}>{nodeValue}</{nodeName}></doc>
trace(xml.toXMLString());

outputs:

<doc>
  <tag>&lt;non-escaped-content&gt;</tag>
</doc>

i admit, this is not CDATA, but i don't see a problem ... parsing requires a little more time, but OTOH, correct escaping much more robust than CDATA ...

the version with XMLNode uses the flash.xml package, which is for backwards compatibility with AS2 ... didn't even notice, it was gone under FP10 ... however, you could use this

var x:XML = new XML("<![CDATA[" + nodeValue + "]]>");

as a replacement and then use appendChild as you would with flash.xml ...

alternatively you could use it e4x style, if you wrap it in a function

function cdata(data:String):XML {
    return = new XML("<![CDATA[" + data + "]]>");
}

and then

var xml:XML = <doc><{nodeName}>{cdata(nodeValue)}</{nodeName}></doc>

but personally, i think that strings, that are both text based and relatively short, should be escaped, rather then wrapped in CDATA ...


update: i don't get your point here

"&lt;" is very different than a "<"

that's what the whole thing is about ... :D ... "<" would be interpreted during parsing, whereas "&lt;" is just reconverted to "<", so after parsing the XML, you will have exactly the same string as before ...

this is my code:

package {
    import flash.display.MovieClip;
    public class Main extends MovieClip {       
        public function Main():void {
            var nodeName:String = "tag";
            var nodeValue:String = "<non-escaped-content>";
            var xml:XML = <doc><{nodeName}>{cdata(nodeValue)}</{nodeName}></doc>;
            trace(cdata("test").toXMLString());
            trace(xml.toXMLString());
        }
        private function cdata(data:String):XML {
            return new XML("<![CDATA[" + data + "]]>");
        }
    }
}

works perfectly for me on flash player 10, compiled with flex sdk 4 ... don't have a flash IDE at hand, but when it comes to pure ActionScript results are almost definitely the same, so it should work (you can use that as your document class, if you want to, or simply instantiate it) ...

btw. the first trace shows, that the second example works, which is also quite obvious, since new XML(<String>) uses the native XML parser to create an XML from the given string ...

here is what the above generates:

<![CDATA[test]]>
<doc>
  <tag><![CDATA[<non-escaped-content>]]></tag>
</doc>

works quite good for me ... :)


greetz

back2dos

Freund answered 6/8, 2009 at 15:54 Comment(3)
Hey, thanks. The reason why I want CDATA is that the method is used to log strings including XML, where a "&lt;" is very different than a "<" of course ... Unfortunately the second solution will convert the tags of the CDATA to "&lt;[CDATA[ ]]&gt;" ignoring the whole signification of the CDATA () :( Did you actually make the 3rd solution work ? This used to work in FP9 but gives me a runtime error in FP10 ?Cytology
I'm not getting the cdata helper function to compile in Flex SDK 3.X anything.Arriola
I'm getting mxml compiler error: "Parse error at '\");\n\t\t}\n\n\n\t\....return new XML("<![CDATA[" + data + "]]>");" I added a compilable implementation of the cdata function below.Arriola
A
7

The above cdata function needs to look like the following, notice the last ">" is escaped in code. Otherwise there's compile errors.

private function cdata(data:String):XML
{
    return new XML("<![CDATA[" + data + "]]\>");                
}
Arriola answered 28/4, 2010 at 13:52 Comment(1)
this method works good for all case but what if my data is ']]>' i'm getting Error "The markup in the document following the root element must be well-formed." while converting to xml. is there any other way to fix it ?Gutenberg
C
2

Thanks, cdata function is very useful. I wrote just new one.

function newNode(nodeName:String,nodeValue:String):XML{
    return new XML(<{nodeName}>{cdata(nodeValue)}</{nodeName}>);
}
Civilian answered 28/4, 2011 at 8:30 Comment(0)
Y
2
private function cdata(data:String, nodeName:String):XML{
    return new XML( "<"+nodeName+"><![CDATA[" + data + "]]\></"+nodeName+">");
}

work fine :)

Yoghurt answered 28/11, 2011 at 2:47 Comment(0)
S
1

Here is another solution

public static function getCDATANode(data:String, tagName:String):void
{
        var node:XML  = new XML(  "<" + tagName + "/>" );
        var cdata:XML = new XML("<![CDATA[" + data + " ]]>");
        node.appendChild(cdata);

        trace("getCDATANode: ", node.toXMLString() );
}
Syntactics answered 13/12, 2012 at 8:3 Comment(0)
B
1

Here's my solution without using functions:

var nodeName:String = "tag";
var nodeValue:String = "<non-escaped-content>";
var xml:XML = <doc><{nodeName}>{new XML("<![CDATA[" + nodeValue + "]]>")}</{nodeName}></doc>;

If you need to replace existing nodes content and keep node attributes you can use:

var newNodeValue:String = "<non-escaped-content>";
var xml:XML = <doc><tag attribute="true">This is node content</tag></doc>;

xml.tag[0].setChildren(new XMLList());
xml.tag[0].appendChild(new XML("<![CDATA[" + newNodeValue + "]]>"));
Bernoulli answered 17/6, 2015 at 13:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.