如何在javascript中转义xml实体?

IT技术 javascript
2021-02-24 07:09:48

在 JavaScript(服务器端 nodejs)中,我正在编写一个生成 xml 作为输出的程序。

我正在通过连接字符串来构建 xml:

str += '<' + key + '>';
str += value;
str += '</' + key + '>';

问题是:如果value包含诸如'&','>'或 之类的字符'<'怎么办?逃避这些角色的最佳方法是什么?

或者是否有任何可以转义 XML 实体的 javascript 库?

6个回答

HTML编码简单地更换&"'<>与他们的实体当量字符。顺序很重要,如果您不先替换&字符,您将对某些实体进行双重编码:

if (!String.prototype.encodeHTML) {
  String.prototype.encodeHTML = function () {
    return this.replace(/&/g, '&amp;')
               .replace(/</g, '&lt;')
               .replace(/>/g, '&gt;')
               .replace(/"/g, '&quot;')
               .replace(/'/g, '&apos;');
  };
}

正如@Johan BW de Vries 指出的那样,这将与标签名称有关,我想澄清一下,我假设这用于value

相反,如果您想解码 HTML 实体1,请确保在其他所有内容之后解码&amp;&以免对任何实体进行双重解码:

if (!String.prototype.decodeHTML) {
  String.prototype.decodeHTML = function () {
    return this.replace(/&apos;/g, "'")
               .replace(/&quot;/g, '"')
               .replace(/&gt;/g, '>')
               .replace(/&lt;/g, '<')
               .replace(/&amp;/g, '&');
  };
}

1只是基础,不包括&copy;to©或其他类似的东西


就图书馆而言。Underscore.js(或Lodash如果你愿意)提供了一个_.escape执行此功能的方法。

@Jonny,正则表达式将提供比多次调用更差的性能.replace()无论哪种情况,您都必须拥有大量数据才能发现任何重大问题。一个更快的替代方法是对您的应用程序进行基准测试并找到实际的阻塞点(通常是嵌套循环),而不是担心像这样可以忽略不计的事情。
2021-04-15 07:09:48
我在 Google 电子表格中有 100-200 行数据。我正在将其转换为 plists (xml) 并且不得不替换那些 xml 实体。为此,我使用上面的代码编写了一个自定义 javascript 函数。它有效,但非常缓慢。电子表格有时会令人窒息,但由于它只是“执行一次”步骤,因此最终速度并不重要。
2021-04-17 07:09:48
我知道这个答案很旧,但只是为了让 JS 的新手清楚:将随机函数(不是某些标准化提案的 polyfill)附加到全局原型是一个坏主意。
2021-04-19 07:09:48
这看起来像是一遍又一遍地替换相同的字符串,这在处理大量数据时可能会影响性能。任何更快的选择?
2021-04-30 07:09:48
这几乎涵盖了 5 个 XML 实体。只需要@apos;
2021-05-15 07:09:48

对于相同的结果,这可能会更有效一些:

function escapeXml(unsafe) {
    return unsafe.replace(/[<>&'"]/g, function (c) {
        switch (c) {
            case '<': return '&lt;';
            case '>': return '&gt;';
            case '&': return '&amp;';
            case '\'': return '&apos;';
            case '"': return '&quot;';
        }
    });
}
这似乎是一个更好的解决方案。为什么没有上涨?
2021-04-25 07:09:48
@Sebastian 啊,这就解释了,谢谢。看看这里的人 ^ ^ ^ ^ 这就是你想要的解决方案!!!
2021-04-25 07:09:48
这让我觉得这是一个比公认的答案更好的解决方案,它遍历整个字符串五次(连续地,减少 JS 引擎优化的范围)寻找与单个字符的匹配;hgoebl的解决方案只遍历输入字符串一次,尝试将每个字符与五个条件之一匹配。问题是什么成本更高:1)遍历字符串;或:2)将每个字符与 5 个可能的字符进行匹配。我的直觉是1)会更昂贵。
2021-04-28 07:09:48
如果输入是 HTML,@RanLottem 解码要复杂得多,请参阅维基百科最好使用解析器(XML 或文档)。
2021-04-29 07:09:48
@VictorGrazi:你的权利,在 50 次测试中有 49 次测试更快的解决方案。也许是因为它比公认的答案年轻近 5 岁。
2021-05-01 07:09:48

如果你有 jQuery,这里有一个简单的解决方案:

  String.prototype.htmlEscape = function() {
    return $('<div/>').text(this.toString()).html();
  };

像这样使用它:

"<foo&bar>".htmlEscape(); -> "&lt;foo&amp;bar&gt"

单引号和双引号一般不需要转义。
2021-05-04 07:09:48
这种技术不会转义单引号和双引号:$('<div/>').text('<&\'>"').html() -> "&lt;&amp;'&gt;""
2021-05-06 07:09:48
我喜欢这种技术,因为它“让浏览器来做”的态度。除了性能较差之外,是否有任何缺点,因为这是通过 DOM API 进行的?
2021-05-09 07:09:48

您可以使用以下方法。我在原型中添加了它以便于访问。我还使用了否定前瞻,因此如果您调用该方法两次或更多次,它不会弄乱事情。

用法:

 var original = "Hi&there";
 var escaped = original.EncodeXMLEscapeChars();  //Hi&amp;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, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
        OutPut = OutPut.replace(/&(?!(amp;)|(lt;)|(gt;)|(quot;)|(#39;)|(apos;))/g, "&amp;");
        OutPut = OutPut.replace(/([^\\])((\\\\)*)\\(?![\\/{])/g, "$1\\\\$2");  //replaces odd backslash(\\) with even.
    }
    else {
        OutPut = "";
    }
    return OutPut;
};
使用此代码,您只需编辑所有应用程序中的所有 String 实例,例如let a = 'foo'将受此代码影响。更好地创建辅助函数而不是扩展原型。
2021-04-24 07:09:48
请不要改变内置对象,因为它会导致冲突,因此是一种非常糟糕的做法。
2021-04-29 07:09:48
被低估的优秀解决方案。确保您不会遇到臭名昭著的 &amp; 输出中的字符串很漂亮。
2021-05-10 07:09:48

注意,如果您在 XML 中有 XML,则所有的正则表达式都不好。
而是循环一次字符串,并替换所有转义字符。
这样,你就不能两次碾压同一个角色。

function _xmlAttributeEscape(inputString)
{
    var output = [];

    for (var i = 0; i < inputString.length; ++i)
    {
        switch (inputString[i])
        {
            case '&':
                output.push("&amp;");
                break;
            case '"':
                output.push("&quot;");
                break;
            case "<":
                output.push("&lt;");
                break;
            case ">":
                output.push("&gt;");
                break;
            default:
                output.push(inputString[i]);
        }


    }

    return output.join("");
}
您对 XML 中的 XML 的观察在我看来是正确的。严格来说,&amp;amp;如果您不希望现有实体(例如)在解码时分解,您可能希望重新转义它们。
2021-04-20 07:09:48