Избегая экранирования ссылок на символьные сущности при создании текстового узла в XML

Я использую методы XML DOM для создания выпадающего меню в JavaScript. После того, как я создаю <option> узел, я добавляю текст, который должен появиться для этой опции. Проблема, с которой я сталкиваюсь, заключается в том, что, когда текст содержит ссылки на символьные объекты (CER), такие как &#8322; символ & CER экранируется &amp;, так что CER, а не символ отображается в меню выбора, когда меню выводится на страницу для отображения. Я пробовал оба следующих метода:

optionNode.appendChild(xmlDoc.createTextNode(label));

а также

optionNode.textContent = label;

и оба дают одинаковый результат. Я могу обойти эту проблему, сделав глобальную замену &amp; с & после того, как я выведу документ XML в текст:

var xml = (new XMLSerializer()).serializeToString(xmlDoc);
return xml.replace(/&amp;/g, '&');

но я уверен, что должен быть способ избежать побега. Любой совет?

2 ответа

Вы могли бы использовать createCDATASection() вместо createTextNode()

var docu = new DOMParser().parseFromString('<xml></xml>',  "application/xml")
var cdata = docu.createCDATASection('Some <CDATA> data & then some');
docu.getElementsByTagName('xml')[0].appendChild(cdata);

alert(new XMLSerializer().serializeToString(docu));
// Displays: <xml><![CDATA[Some <CDATA> data & then some]]></xml>

Я нашел решение. Прежде чем создать узел, содержащий labelЯ конвертирую все ссылки на сущности персонажа в label Unicode символов. Затем при выводе xml в виде строки я преобразую все символы Unicode обратно в ссылки на объекты символов. Код адаптирован из кода, который я нашел в другом месте в переполнении стека.

function cerToUnicode(str) {
    "use strict";
    var entity_table = {
       '&quot;': String.fromCharCode(34), // Quotation mark. Not required
       '&amp;': String.fromCharCode(38), // Ampersand
               '&lt;': String.fromCharCode(60), // Less-than sign
       '&gt;': String.fromCharCode(62), // Greater-than sign
       '&nbsp;': String.fromCharCode(160), // Non-breaking space
       '&iexcl;': String.fromCharCode(161), // Inverted exclamation mark
       ... // other named CERs
   };
   str = str.replace(/&#(\d+);/g,
       function (matched, capture1) {
           return (capture1 == '38' ? '&amp;' : String.fromCharCode(capture1));
       });
   str = str.replace(/&[^;]*;/g,
       function (matched) {
           return entity_table[matched];
       });
   return str;
} // cerToUnicode()

function unicodeToCER(str) {
    return str.replace(/./gm, function(s) {
        var code = s.charCodeAt(0);
        return (code < 128 ? s : "&#" + code + ";");
    });
} // unicodeToCER()
Другие вопросы по тегам