在 JavaScript(服务器端 NodeJS)中,我正在编写一个生成 XML 作为输出的程序。
我通过连接字符串来构建 XML:
str += '<' + key + '>';
str += value;
str += '</' + key + '>';
问题是:如果
value
包含'&'
、'>'
或'<'
等字符怎么办?
逃离这些角色的最佳方法是什么?
或者是否有任何 JavaScript 库可以转义 XML 实体?
对于相同的结果,这可能会更有效一些:
function escapeXml(unsafe) {
return unsafe.replace(/[<>&'"]/g, function (c) {
switch (c) {
case '<': return '<';
case '>': return '>';
case '&': return '&';
case '\'': return ''';
case '"': return '"';
}
});
}
HTML 编码只是将
&
、"
、'
、<
和 >
字符替换为其实体等效项。顺序很重要,如果您不首先替换 &
字符,您将对某些实体进行双重编码:
if (!String.prototype.encodeHTML) {
String.prototype.encodeHTML = function () {
return this.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
};
}
如@Johan B.W. de Vries 指出,这会对标签名称产生问题,我想澄清一下,我假设这是用于
value
only
相反,如果您想解码 HTML 实体1,请确保在完成其他操作之后将
&
解码为 &
,这样就不会双重解码任何实体:
if (!String.prototype.decodeHTML) {
String.prototype.decodeHTML = function () {
return this.replace(/'/g, "'")
.replace(/"/g, '"')
.replace(/>/g, '>')
.replace(/</g, '<')
.replace(/&/g, '&');
};
}
1只是基础知识,不包括
©
到©
或其他类似的东西
就图书馆而言。 Underscore.js(或 Lodash,如果您愿意)提供了一个
_.escape
方法来执行此功能。
如果您有 jQuery,这里有一个简单的解决方案:
String.prototype.htmlEscape = function() {
return $('<div/>').text(this.toString()).html();
};
像这样使用它:
"<foo&bar>".htmlEscape();
-> "<foo&bar>"
您可以使用以下方法。我已将其添加到原型中以便于访问。 我还使用了负前瞻,因此如果您调用该方法两次或更多次,它不会弄乱事情。
用途:
var original = "Hi&there";
var escaped = original.EncodeXMLEscapeChars(); //Hi&there
解码由 XML 解析器自动处理。
方法:
//String Extenstion to format string for xml content.
//Replces xml escape chracters to their equivalent html notation.
String.prototype.EncodeXMLEscapeChars = function () {
var OutPut = this;
if ($.trim(OutPut) != "") {
OutPut = OutPut.replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
OutPut = OutPut.replace(/&(?!(amp;)|(lt;)|(gt;)|(quot;)|(#39;)|(apos;))/g, "&");
OutPut = OutPut.replace(/([^\\])((\\\\)*)\\(?![\\/{])/g, "$1\\\\$2"); //replaces odd backslash(\\) with even.
}
else {
OutPut = "";
}
return OutPut;
};
注意,如果 XML 中有 XML,那么所有的正则表达式都不好。
相反,循环字符串一次,并替换所有转义字符。
这样,您就不能两次碰到同一个角色。
function _xmlAttributeEscape(inputString)
{
var output = [];
for (var i = 0; i < inputString.length; ++i)
{
switch (inputString[i])
{
case '&':
output.push("&");
break;
case '"':
output.push(""");
break;
case "<":
output.push("<");
break;
case ">":
output.push(">");
break;
default:
output.push(inputString[i]);
}
}
return output.join("");
}
我最初在生产代码中使用了已接受的答案,发现大量使用时它实际上非常慢。这是一个更快的解决方案(以两倍以上的速度运行):
var escapeXml = (function() {
var doc = document.implementation.createDocument("", "", null)
var el = doc.createElement("temp");
el.textContent = "temp";
el = el.firstChild;
var ser = new XMLSerializer();
return function(text) {
el.nodeValue = text;
return ser.serializeToString(el);
};
})();
console.log(escapeXml("<>&")); //<>&
const escapeXml = (unsafe) =>
unsafe.replace(/[<>&'"]/g, (c) => `&${({
'<': 'lt',
'>': 'gt',
'&': 'amp',
'\'': 'apos',
'"': 'quot'
})[c]};`);
function escape(text) {
return String(text).replace(/(['"<>&'])(\w+;)?/g, (match, char, escaped) => {
if(escaped) {
return match;
}
switch(char) {
case '\'': return ''';
case '"': return '"';
case '<': return '<';
case '>': return '>';
case '&': return '&';
}
});
}
sText = ("" + sText).split("<").join("<").split(">").join(">").split('"').join(""").split("'").join("'");