Unescape HTML entities в 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/
каковы другие способы диагностики проблемы?
10 ответов:
Я использую следующий метод:
function htmlDecode(input){ var e = document.createElement('div'); 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 символьные сущности.
EDIT: старая версия этого код не работал на IE с пустыми входами, о чем свидетельствует здесь на jsFiddle (смотреть в IE). Версия выше работает со всеми входами.
UPDATE: кажется, это не работает с большой строкой, а также вводит уязвимость системы безопасности см. комментарии.
большинство ответов, приведенных здесь, имеют огромный недостаток: если строка, которую вы пытаетесь преобразовать, не доверена, то вы получите уязвимость межсайтового скриптинга (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 (обычно они все еще недостаточно многочисленны, чтобы беспокоиться).
Если вы используете jQuery:
function htmlDecode(value){ return $('<div/>').html(value).text(); }в противном случае, используйте строго объект кодировщика программного обеспечения, который имеет отличную
трюк заключается в использовании мощности браузера для декодирования специальных символов 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 }); }
Крис ответ хороший и элегантный, но это не удается, если значение неопределено. Просто простое улучшение делает его твердым:
function htmlDecode(value) { return (typeof value === 'undefined') ? '' : $('<div/>').html(value).text(); }
ответ 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 и построить
<img>С помощью самого javascript.структура, которую вы получаете от RPC, может выглядеть так:
{"img" : ["myimage.jpg", "myimage2.jpg"]}Я думаю, что это лучше таким образом, как инъекции кода, который поступает из внешних источник на Вашей странице не выглядит очень безопасным. Визуализация кого-то, кто захватывает ваш сценарий XML-RPC и помещает туда то, что вам не нужно (даже некоторые javascript...)
это лучше:
String::decode = -> $('<textarea />').html(this).text()использование:
"<img src='myimage.jpg'>".decode();
Я использую это в моем проекте: вдохновленный другие ответы но с дополнительным безопасным параметром, может быть полезно, когда вы имеете дело с украшенными символами
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>';
все остальные ответы здесь есть проблемы.
документ.методы 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 используется специально, чтобы избежать executig JS кода. Он передает эти:
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.
Comments