我有一些与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/
诊断这个问题的其他方法是什么?
编辑:你应该像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("<img src='myimage.jpg'>");
// returns "<img src='myimage.jpg'>"
基本上,我以编程方式创建了一个DOM元素,将编码的HTML分配给它的innerHTML,并从innerHTML插入上创建的文本节点检索nodeValue。因为它只是创建了一个元素,而没有添加它,所以没有修改站点HTML。
它将跨浏览器(包括旧浏览器)工作,并接受所有的HTML字符实体。
编辑:这段代码的旧版本不能在IE空白输入上工作,正如jsFiddle (IE中的视图)上所证明的那样。上面的版本适用于所有输入。
更新:这似乎不工作与大字符串,它也引入了一个安全漏洞,见评论。
CMS的答案很好,除非你想要取消转义的HTML非常长,超过65536个字符。因为在Chrome中,内部HTML被分割成许多子节点,每个子节点最长65536个,你需要将它们连接起来。这个函数也适用于很长的字符串:
function unencodeHtmlContent(escapedHtml) {
var elem = document.createElement('div');
elem.innerHTML = escapedHtml;
var result = '';
// Chrome splits innerHTML into many child nodes, each one at most 65536.
// Whereas FF creates just one single huge child node.
for (var i = 0; i < elem.childNodes.length; ++i) {
result = result + elem.childNodes[i].nodeValue;
}
return result;
}
有关innerHTML最大长度的更多信息,请参阅以下答案:https://stackoverflow.com/a/27545633/694469
不是对你的问题的直接回应,但它不是更好为您的RPC返回一些结构(是XML或JSON或其他)与那些图像数据(在您的例子中的url)在该结构?
然后你可以在javascript中解析它,并使用javascript本身构建<img>。
你从RPC接收到的结构可能是这样的:
{"img" : ["myimage.jpg", "myimage2.jpg"]}
我认为这样更好,因为将来自外部源代码的代码注入您的页面看起来不太安全。想象一下,有人劫持了您的XML-RPC脚本,并在其中放入了一些您不想要的东西(甚至是一些javascript……)
首先创建一个<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
Matthias Bynens有一个这样的库:https://github.com/mathiasbynens/he
例子:
console.log(
he.decode("Jörg & Jürgen rocked to & 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 & 2')); // '1 & 2'
但是请注意安全问题,影响类似的方法,我在链接的答案中列出!这种方法是一种hack,将来对文本区域允许内容的更改(或特定浏览器中的错误)可能会导致依赖它的代码有一天突然出现XSS漏洞。