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/



каковы другие способы диагностики проблемы?

759   10  

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("&lt;img src='myimage.jpg'&gt;"); 
// 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("&lt;img src='myimage.jpg'&gt;");

// 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()

использование:

"&lt;img src='myimage.jpg'&gt;".decode();

от: HTML Entity Decode

Я использую это в моем проекте: вдохновленный другие ответы но с дополнительным безопасным параметром, может быть полезно, когда вы имеете дело с украшенными символами

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>';

все остальные ответы здесь есть проблемы.

документ.методы 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('&lt;&amp;&nbsp;&gt;'); // 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

    Ничего не найдено.