Javascript 使用 XMLSerializer 序列化 CDATA

Javascript serializing CDATA with XMLSerializer

我正在尝试寻找一种跨浏览器的方式来序列化包含 CDATA 的 SVG 文档。

我的代码在 Chrome 和 Firefox 上运行良好,但在 Internet Explorer 上,CDATA 被序列化为文本而不是 CDATA 部分。到目前为止,这是我的实现:

var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
var xml = new DOMParser().parseFromString('<xml></xml>',  "application/xml");
var cdata = xml.createCDATASection('Some data & some more');
svg.appendChild(cdata);
log("Node Type: " + cdata.nodeName)
log("SVG: " + new XMLSerializer().serializeToString(svg));


// Utility function for output
function log(s) {
  var output = document.getElementById('output');
  if (output) {
    output.innerHTML += new Option(s).innerHTML + '<br>';
  } else {
    console.log(s);
  }
} 
<div id="output"></div>

在 Chrome 和 Firefox 上,XMLSerializer 的输出符合预期:
<svg xmlns="http://www.w3.org/2000/svg"><![CDATA[Some data & some more]]></svg>

但在 Internet Explorer 上,CDATA 被写为一个简单的文本节点:
<svg xmlns="http://www.w3.org/2000/svg">Some data &amp; some more</svg>

我尝试在“”中添加包装 CDATA 部分的数据,但这不起作用,因为它会被转义。有什么办法可以使 Internet Explorer 正确写入 CDATA 部分吗?

注意:如果代码片段嵌入到 Whosebug 中,则无法在 Internet Explorer 中使用,但它可以作为独立文件使用。

我想出了一个 hacky 解决方案,虽然不是很令人满意,但它确实有效。

在序列化之前,cdata 的数据被开始和结束标记包围(我使用的是 __CDATACDATA__,在序列化之后,使用正则表达式替换标记(以及可选的 CDATA 开始和结束标签)由 CDATA 开始和结束标签。

可以选择使用浏览器嗅探来检测是否有必要进行这种黑客攻击。

这里是修改后的例子:

var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
var xml = new DOMParser().parseFromString('<xml></xml>',  "application/xml");
var cdata = xml.createCDATASection('Some data & some more');
// Add markers
cdata.data = "__CDATA" + cdata.data + "CDATA__";
svg.appendChild(cdata);
var svgStr = new XMLSerializer().serializeToString(svg);
// Replace markers (and already existing CDATA start and end tags)
svgStr = svgStr.replace(/(?:<\!\[CDATA\[)?__CDATA(.*?)CDATA__(?:\]\]>)?/g, '<![CDATA[]]>');

log("SVG: " + svgStr);



// Utility function for output
function log(s) {
  var output = document.getElementById('output');
  if (output) {
    output.innerHTML += new Option(s).innerHTML + '<br>';
  } else {
    console.log(s);
  }
} 
<div id="output"></div>