我有一些与XML-RPC后端通信的JavaScript代码。 XML-RPC返回如下形式的字符串:

<img src='myimage.jpg'>

然而,当我使用JavaScript将字符串插入到HTML中时,它们会逐字呈现。我看到的不是图像,而是字符串:

<img src='myimage.jpg'>

我猜想HTML是通过XML-RPC通道转义的。

如何在JavaScript中解除字符串转义?我尝试了这个页面上的技巧,但没有成功:http://paulschreiber.com/blog/2008/09/20/javascript-how-to-unescape-html-entities/

诊断这个问题的其他方法是什么?


当前回答

Matthias Bynens有一个这样的库:https://github.com/mathiasbynens/he

例子:

console.log(
    he.decode("J&#246;rg &amp J&#xFC;rgen rocked to &amp; fro ")
);
// Logs "Jörg & Jürgen rocked to & fro"

我建议使用它,而不是设置元素的HTML内容,然后读取它的文本内容。这种方法是可行的,但如果用于不可信的用户输入,则具有欺骗性的危险,并提供XSS机会。

如果你真的不能忍受在库中加载,你可以使用这个回答中描述的textarea黑客来回答一个几乎重复的问题,这与各种类似的方法不同,没有我所知道的安全漏洞:

function decodeEntities(encodedString) {
    var textArea = document.createElement('textarea');
    textArea.innerHTML = encodedString;
    return textArea.value;
}

console.log(decodeEntities('1 &amp; 2')); // '1 & 2'

但是请注意安全问题,影响类似的方法,我在链接的答案中列出!这种方法是一种hack,将来对文本区域允许内容的更改(或特定浏览器中的错误)可能会导致依赖它的代码有一天突然出现XSS漏洞。

其他回答

编辑:你应该像Wladimir建议的那样使用DOMParser API,我编辑了我之前的答案,因为发布的函数引入了安全漏洞。

下面的代码片段是老答案的代码,只做了一些小修改:使用textarea而不是div减少了XSS漏洞,但在IE9和Firefox中仍然存在问题。

function htmlDecode(input){
  var e = document.createElement('textarea');
  e.innerHTML = input;
  // handle case of empty input
  return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
}

htmlDecode("&lt;img src='myimage.jpg'&gt;"); 
// returns "<img src='myimage.jpg'>"

基本上,我以编程方式创建了一个DOM元素,将编码的HTML分配给它的innerHTML,并从innerHTML插入上创建的文本节点检索nodeValue。因为它只是创建了一个元素,而没有添加它,所以没有修改站点HTML。

它将跨浏览器(包括旧浏览器)工作,并接受所有的HTML字符实体。

编辑:这段代码的旧版本不能在IE空白输入上工作,正如jsFiddle (IE中的视图)上所证明的那样。上面的版本适用于所有输入。

更新:这似乎不工作与大字符串,它也引入了一个安全漏洞,见评论。

这个问题没有指定x的来源,但如果可以的话,它有意义,可以防御恶意(或来自我们自己的应用程序的意外)输入。例如,假设x的值为&< >脚本alert('你好');> < /脚本。在jQuery中处理这个问题的一个安全而简单的方法是:

var x    = "&amp; <script>alert('hello');</script>";
var safe = $('<div />').html(x).text();

// => "& alert('hello');"

可以通过https://gist.github.com/jmblog/3222899找到。我想不出有什么理由不使用这个解决方案,因为它至少和其他解决方案一样短(如果不是更短的话),并且提供了对XSS的防御。

(我最初是作为评论发布这篇文章的,但由于同一线程中的后续评论要求我这样做,所以我将其作为回答添加进来)。

我在我的项目中使用了这个方法:受到其他答案的启发,但有一个额外的安全参数,在处理装饰字符时很有用

var decodeEntities=(function(){

    var el=document.createElement('div');
    return function(str, safeEscape){

        if(str && typeof str === 'string'){

            str=str.replace(/\</g, '&lt;');

            el.innerHTML=str;
            if(el.innerText){

                str=el.innerText;
                el.innerText='';
            }
            else if(el.textContent){

                str=el.textContent;
                el.textContent='';
            }

            if(safeEscape)
                str=str.replace(/\</g, '&lt;');
        }
        return str;
    }
})();

它的可用性如下:

var label='safe <b> character &eacute;ntity</b>';
var safehtml='<div title="'+decodeEntities(label)+'">'+decodeEntities(label, true)+'</div>';

一个javascript解决方案,捕捉常见的:

var map = {amp: '&', lt: '<', gt: '>', quot: '"', '#039': "'"}
str = str.replace(/&([^;]+);/g, (m, c) => map[c])

这是https://stackoverflow.com/a/4835406/2738039的反面

首先创建一个<span id="decodeIt" style="display:none;></span>在身体某处

接下来,将要解码为innerHTML的字符串赋值如下:

document.getElementById("decodeIt").innerHTML=stringtodecode

最后,

stringtodecode=document.getElementById("decodeIt").innerText

下面是整个代码:

var stringtodecode="<B>Hello</B> world<br>";
document.getElementById("decodeIt").innerHTML=stringtodecode;
stringtodecode=document.getElementById("decodeIt").innerText