Javascript to add cdata section on the fly?

I'm having trouble with special characters that exist in an xml node attribute. To combat this, I'm trying to render the attributes as child nodes and, where necessary, using cdata sections to get around the special characters. The problem is, I can't seem to get the cdata section appended to the node correctly.

I'm iterating over the source xml node's attributes and creating new nodes. If the attribute.name = "description" I want to put the attribute.text() in a cdata section and append the new node. That's where I jump the track.

     // newXMLData is the new xml document that I've created in memory
    for (var ctr =0;ctr< this.attributes.length;ctr++){  // iterate over the attributes 
          if( this.attributes[ctr].name =="Description"){   // if the attribute name is "Description" add a CDATA section 
             var thisNodeName =  this.attributes[ctr].name;
               newXMLDataNode.append("<"+thisNodeName +"></"+ thisNodeName +">" );
               var cdata = newXMLData.createCDATASection('test');  // here's where it breaks. 
          } else {
           // It's not "Description" so just append the new node.
            newXMLDataNode.append("<"+ this.attributes[ctr].name +">" + $(this.attributes[ctr]).text() + "</"+ this.attributes[ctr].name +">"   );  
          }        
        } 

Any ideas? Is there another way to add a cdata section?

Here's a sample snippet of the source...

<row 
pSiteID="4" 
pSiteTile="Test Site Name " 
pSiteURL="http://www.cnn.com"
ID="1" 
Description="<div>blah blah blah since June 2007.&amp;nbsp; T<br>&amp;nbsp;<br>blah blah blah blah&amp;nbsp; </div>" 
CreatedDate="2010-09-20 14:46:18" 
Comments="Comments example.&#10;" >

here's what I'm trying to create...

<Site>
<PSITEID>4</PSITEID>
<PSITETILE>Test Site Name</PSITETILE>
<PSITEURL>http://www.cnn.com</PSITEURL>
<ID>1</ID>
<DESCRIPTION><![CDATA[<div>blah blah blah since June 2007.&amp;nbsp; T<br>&amp;nbsp;<br>blah blah blah blah&amp;nbsp; </div ]]></DESCRIPTION>
<CREATEDDATE>2010-09-20 14:46:18</CREATEDDATE>
<COMMENTS><![CDATA[ Comments example.&#10;]]></COMMENTS>
</Site>

Answers:

Answer

I had the same issue. i was trying to append CDATA to xml nodes, so i thought its as easy as adding like so:

valueNode[0].text = "<![CDATA["+ tmpVal +"]]>";
//valueNode[0] represents "<value></value>"

This does not work because the whole thing will get interpreted as text therefore <(less than) and > (great than) will be replaced automatically.

what you need to do is use createCDATASection by doing the following:

var tmpCdata = $xmlDoc[0].createCDATASection(escape("muzi test 002"));
//i'm also escaping special charactures as well
valueNode[0].appendChild(tmpCdata);

results will be:

<value><![CDATA[muzi%20test%20002]]></value>

Brettz9 (in previous answer) explains how to do this but quite complex, therefore i just wanted to add my solution which is much simpler.

thanks,

Answer

Not sure of browser support for document.implementation.createDocument or createCDataSection, but this works in Mozilla at least:

<script>

    // Define some helpers (not available IE < 9)
    function parse (str) {
        return new DOMParser().parseFromString(str, 'text/xml').documentElement;
    }
    function ser (dom) {
        return new XMLSerializer().serializeToString(dom);
    }

    // Simulate your XML retrieval
    var row = '<row pSiteID="4" pSiteTile="Test Site Name " pSiteURL="http://www.cnn.com" ID="1" Description="<div>blah blah blah since June 2007.&amp;nbsp; T<br>&amp;nbsp;<br>blah blah blah blah&amp;nbsp; </div>" CreatedDate="2010-09-20 14:46:18" Comments="Comments example.&#10;" />';

    // Hack to convert source to well-formed XML, or otherwise you can't use DOM methods on it which
    // depend on well-formed XML
    row = row.replace(/(=\s*")([\s\S]*?)(")/g, function (n0, n1, n2, n3) {
        return n1+ // Add back equal sign and opening quote
            n2.replace(/</g, '&lt;'). // Create well-formed XML by avoiding less-than signs inside attributes
            replace(/&amp;nbsp;/g, '&amp;#160;')+ // HTML entities (except for gt, lt, amp, quot) must be either converted to numeric character references or your XML must define the same entities
            n3; // Add back closing quote
    });

    // Simulate your retrieval of DOM attributes, though in this context, we're just making attributes into a global
    this.attributes = parse(row).attributes;

    // Simulate your creation of an XML document
    var newXMLData = document.implementation.createDocument(null, 'Site', null);

    // Modify your code to avoid jQuery dependency for easier testing and to 
    // avoid confusion (error?) of having two variables, newXMLData and newXMLDataNode
    for (var ctr =0;ctr< this.attributes.length;ctr++){  // iterate over the attributes 
      if (this.attributes[ctr].name =="Description") {   // if the attribute name is "Description" add a CDATA section 
         var thisNodeName =  this.attributes[ctr].name;
         var str = "<"+thisNodeName +"></"+ thisNodeName +">";
         var node = parse(str);
         var cdata = newXMLData.createCDATASection(this.attributes[ctr].textContent);
         node.appendChild(cdata);
         newXMLData.documentElement.appendChild(node);       
      }
      else {
       // It's not "Description" so just append the new node.
        var str= "<"+ this.attributes[ctr].name +">" + this.attributes[ctr].textContent + "</"+ this.attributes[ctr].name +">";
        newXMLData.documentElement.appendChild(parse(str));
      }
    } 
    // Prove its working (though you may wish to use toUpperCase() if you need the element names upper-cased); 
    // if you need CDATA for Comments, you can follow the pattern above to add support for that too
    alert(ser(newXMLData)); 
</script>

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us Javascript

©2020 All rights reserved.