Unescape HTML-объекты в Javascript?
У меня есть код Javascript, который взаимодействует с базой данных XML-RPC.
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/
Каковы другие способы диагностики проблемы?
Ответы
Ответ 1
ОБНОВЛЕНИЕ: Вы должны использовать API DOMParser, поскольку Владимир предлагает, я отредактировал свой предыдущий ответ, поскольку опубликованная функция представила уязвимость безопасности.
Следующий фрагмент кода представляет собой старый код ответа с небольшой модификацией: использование 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 и извлекаю nodeValue из текстового узла, созданного при вставке innerHTML. Поскольку он просто создает элемент, но никогда не добавляет его, HTML-код сайта не изменяется.
Он будет работать в кросс-браузерном режиме (включая старые браузеры) и принимать все символьные объекты HTML.
ОБНОВЛЕНИЕ: старая версия этого кода не работала в IE с пустыми вводами, о чем свидетельствует здесь на jsFiddle (просмотр в IE). Вышеприведенная версия работает со всеми входами.
ОБНОВЛЕНИЕ: кажется, это не работает с большой строкой, и это также вводит уязвимость безопасности, см. комментарии.
Ответ 2
Большинство приведенных здесь ответов имеют огромный недостаток: если строка, которую вы пытаетесь преобразовать, не доверяет, вы получите Межсайтовый скриптинг (XSS). Для функции в принятом ответе рассмотрите следующее:
htmlDecode("<img src='dummy' onerror='alert(/xss/)'>");
В этой строке содержится неопределенный HTML-тег, поэтому вместо декодирования чего-либо функция htmlDecode
на самом деле запускает код JavaScript, указанный внутри строки.
Этого можно избежать, используя DOMParser, который поддерживается в все современные браузеры:
function htmlDecode(input)
{
var doc = new DOMParser().parseFromString(input, "text/html");
return doc.documentElement.textContent;
}
// This returns "<img src='myimage.jpg'>"
htmlDecode("<img src='myimage.jpg'>");
// This returns ""
htmlDecode("<img src='dummy' onerror='alert(/xss/)'>");
Эта функция, как гарантируется, не будет запускать какой-либо код JavaScript в качестве побочного эффекта. Любые теги HTML будут проигнорированы, будет возвращен только текстовый контент.
Примечание по совместимости: для анализа HTML с DOMParser
требуется, по крайней мере, Chrome 30, Firefox 12, Opera 17, Internet Explorer 10, Safari 7.1 или Microsoft Edge. Таким образом, все браузеры без поддержки проходят мимо EOL, и по состоянию на 2017 год единственными, которые по-прежнему могут быть замечены в дикой природе, являются более старые версии Internet Explorer и Safari (обычно их все еще недостаточно, чтобы беспокоиться).
Ответ 3
Если вы используете jQuery:
function htmlDecode(value){
return $('<div/>').html(value).text();
}
В противном случае используйте Strictly Software Encoder Object, который имеет отличную функцию htmlDecode()
.
Ответ 4
Хитрость заключается в использовании мощности браузера для декодирования специальных символов HTML, но не позволяет браузеру выполнять результаты, как если бы это был фактический html... Эта функция использует регулярное выражение для идентификации и замены закодированных HTML-символов, по одному символу за раз.
function unescapeHtml(html) {
var el = document.createElement('div');
return html.replace(/\&[#0-9a-z]+;/gi, function (enc) {
el.innerHTML = enc;
return el.innerText
});
}
Ответ 5
Ответ 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
max length для получения дополнительной информации: fooobar.com/questions/65916/...
Ответ 6
Не прямой ответ на ваш вопрос, но не лучше ли для вашего RPC вернуть некоторую структуру (будь то XML или JSON или что-то еще) с этими данными изображения (URL-адреса в вашем примере) внутри этой структуры?
Затем вы можете просто проанализировать его в своем javascript и построить <img>
с помощью самого javascript.
Структура, которую вы получите из RPC, может выглядеть так:
{"img" : ["myimage.jpg", "myimage2.jpg"]}
Я думаю, что так лучше, поскольку ввод кода, который поступает из внешнего источника на вашу страницу, выглядит не очень безопасным. Изображая кого-то, угоняющего ваш XML-RPC script, и помещайте что-то, чего вы не хотели бы там (даже некоторый javascript...)
Ответ 7
Ответ Криса приятный и элегантный, но он терпит неудачу, если значение undefined. Простое улучшение делает его прочным:
function htmlDecode(value) {
return (typeof value === 'undefined') ? '' : $('<div/>').html(value).text();
}
Ответ 8
Не за что... просто посыльный... полный кредит переходит на ourcodeworld.com, ссылка ниже.
window.htmlentities = {
/**
* Converts a string to its html characters completely.
*
* @param {String} str String with unescaped HTML characters
**/
encode : function(str) {
var buf = [];
for (var i=str.length-1;i>=0;i--) {
buf.unshift(['&#', str[i].charCodeAt(), ';'].join(''));
}
return buf.join('');
},
/**
* Converts an html characterSet into its original character.
*
* @param {String} str htmlSet entities
**/
decode : function(str) {
return str.replace(/&#(\d+);/g, function(match, dec) {
return String.fromCharCode(dec);
});
}
};
Полный кредит: https://ourcodeworld.com/articles/read/188/encode-and-decode-html-entities-using-pure-javascript
Ответ 9
Это лучше:
String::decode = ->
$('<textarea />').html(this).text()
использование:
"<img src='myimage.jpg'>".decode();
from: Декодирование HTML-объектов
Ответ 10
Я использую это в своем проекте: вдохновленный другими ответами, но с дополнительным безопасным параметром, может быть полезен, когда вы имеете дело с украшенными символами
var decodeEntities=(function(){
var el=document.createElement('div');
return function(str, safeEscape){
if(str && typeof str === 'string'){
str=str.replace(/\</g, '<');
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, '<');
}
return str;
}
})();
И это применимо как:
var label='safe <b> character éntity</b>';
var safehtml='<div title="'+decodeEntities(label)+'">'+decodeEntities(label, true)+'</div>';
Ответ 11
Все остальные ответы здесь имеют проблемы.
Методы document.createElement('div') (включая те, которые используют jQuery) выполняют любой переданный в него javascript (проблема безопасности), а метод DOMParser.parseFromString() обрезает пробелы. Вот чистое решение для JavaScript, которое не имеет проблем:
function htmlDecode(html) {
var textarea = document.createElement("textarea");
html= html.replace(/\r/g, String.fromCharCode(0xe000)); // Replace "\r" with reserved unicode character.
textarea.innerHTML = html;
var result = textarea.value;
return result.replace(new RegExp(String.fromCharCode(0xe000), 'g'), '\r');
}
TextArea используется специально для того, чтобы избежать выполнения кода jQuery. Он передает следующее:
htmlDecode('<& >'); // returns "<& >" with non-breaking space.
htmlDecode(' '); // returns " "
htmlDecode('<img src="dummy" onerror="alert(\'xss\')">'); // Does not execute alert()
htmlDecode('\r\n') // returns "\r\n", doesn't lose the \r like other solutions.
Ответ 12
Вместо экранирования строки, запретите пользователю вводить одну строку
function EscapeInputValue(inputValue) {
return /^(?:[^\<\>\<\\\>]*)(?:[^\<\>\<\\\>]*)$/.test(inputValue);
}
Ура! :)
Ответ 13
Есть вариант, который на 80% продуктивнее ответов на самом верху.
См. Тест: https://jsperf.com/decode-html12345678/1
![performance test]()
console.log(decodeEntities('test: >'));
function decodeEntities(str) {
// this prevents any overhead from creating the object each time
const el = decodeEntities.element || document.createElement('textarea')
// strip script/html tags
el.innerHTML = str
.replace(/<script[^>]*>([\S\s]*?)<\/script>/gmi, '')
.replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/gmi, '');
return el.value;
}