Como decodificar entidades HTML usando jQuery?

334

Como uso o jQuery para decodificar entidades HTML em uma string?

EddyR
fonte
A escolha prematura da tecnologia (jQuery) convida a respostas com problemas de segurança. Pode ser melhor fechar como uma duplicata de stackoverflow.com/questions/1912501/… .
Wladimir Palant 26/02

Respostas:

437

Nota de segurança: o uso desta resposta (preservada em sua forma original abaixo) pode introduzir uma vulnerabilidade XSS no seu aplicativo. Você não deve usar esta resposta. Leia a resposta de lucascaro para obter uma explicação das vulnerabilidades nesta resposta e use a abordagem dessa resposta ou a resposta de Mark Amery .

Na verdade, tente

var decoded = $("<div/>").html(encodedStr).text();
tom
fonte
175
Você não fazer isso com entrada não confiável. Muitos navegadores carregam imagens e acionam eventos relacionados, mesmo que o nó não esteja conectado ao DOM. Tente correr $("<div/>").html('<img src="http://www.google.com/images/logos/ps_logo2.png" onload=alert(1337)>'). No Firefox ou Safari, ele dispara o alerta.
Mike Samuel
@ Mike, então o que você recomenda? sua resposta de .replace () não é bom se você não sabe o que você está substituindo ...
ekkis
7
@ekkis, você precisa remover as tags antes de tentar decodificar entidades. str.replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/g, "")ou algo semelhante.
Mike Samuel
2
Uma implementação melhor (na minha opinião) que retira a maioria das tags HTML (cortesia de Mike) da entrada está na minha resposta a uma pergunta semelhante . Ele também não possui a sobrecarga do jQuery, portanto é bastante adequado para outros ambientes.
Robert K
6
@MichaelStum sua edição aqui invalidou o comentário de Mike Samuel e a resposta com a maior votação, sem o conserto da vulnerabilidade XSS para todas as versões do jQuery (como explicado na resposta abaixo). Adicionar um aviso de segurança a esta resposta seria razoável (e vou fazer isso); tornar outras discussões nesta página sem sentido e falhar em consertar a falha de segurança definitivamente não é!
Mark Amery
211

Sem jQuery:

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

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

Isso funciona de maneira semelhante à resposta aceita , mas é seguro para uso com entradas não confiáveis ​​do usuário.


Problemas de segurança em abordagens semelhantes

Como observado por Mike Samuel , fazendo isso com um <div>em vez de um <textarea>com a entrada do usuário não confiável é uma vulnerabilidade de XSS, mesmo se a <div>nunca é adicionado ao DOM:

function decodeEntities(encodedString) {
  var div = document.createElement('div');
  div.innerHTML = encodedString;
  return div.textContent;
}

// Shows an alert
decodeEntities('<img src="nonexistent_image" onerror="alert(1337)">')

No entanto, esse ataque não é possível contra a <textarea>porque não há elementos HTML com conteúdo permitido de a <textarea>. Consequentemente, qualquer tag HTML ainda presente na string 'codificada' será automaticamente codificada por entidade pelo navegador.

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

// Safe, and returns the correct answer
console.log(decodeEntities('<img src="nonexistent_image" onerror="alert(1337)">'))

Aviso : Fazer isso usando jQuery .html()e .val()métodos em vez de usar .innerHTMLe .valuetambém é inseguro * para algumas versões do jQuery, mesmo ao usar atextarea . Isso ocorre porque as versões mais antigas do jQuery avaliam deliberada e explicitamente os scripts contidos na cadeia de caracteres transmitida .html(). Portanto, um código como este mostra um alerta no jQuery 1.8:

//<!-- CDATA
// Shows alert
$("<textarea>")
.html("<script>alert(1337);</script>")
.text();

//-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>

* Obrigado a Eru Penkman por capturar esta vulnerabilidade.

lucascaro
fonte
6
Pode ser uma boa idéia destruir a área de texto após extrair seu valor:decodedString = textArea.value; textArea.remove(); return decodedString;
Werner
2
Ou apenas se a versão do javascript realmente suportar remove ():if ('remove' in Element.prototype) textArea.remove();
Werner
6
@Werner Assim que a função for encerrada, não haverá mais variáveis ​​mantendo uma referência a ela; portanto, ela será removida automaticamente pelo coletor de lixo .
precisa saber é o seguinte
Estou usando isso em combinação com o .NET do code-behind de um clique no botão e, por algum motivo, a resposta aceita causou uma postagem. Esta resposta não foi, então esta é a melhor resposta para mim. Obrigado!
Snailer
O @Snailer $("<div />").html(string).text() executará qualquer javascript na string fornecida , que eu suspeito é o que estava causando o seu problema. A resposta aceita deve ser atualizada para esta.
jbowman
80

Como Mike Samuel disse, não use jQuery.html (). Text () para decodificar entidades html, pois é inseguro.

Em vez disso, use um processador de modelo como Mustache.js ou decodeEntities de @ comentário de VyvIT.

A biblioteca de utilitários do Underscore.js é fornecida com métodos escapee unescape, mas eles não são seguros para a entrada do usuário:

_.escape (string)

_.unescape (string)

Alan Hamlett
fonte
2
Isso realmente merece muito mais votos! Definitivamente minha solução preferida. Eles incluíram unescapeos documentos até agora, btw.
Lethal-guitar
5
_.unescape("&#39;")resulta em apenas "& # 39;" em vez de aspas simples. Existe algo que eu estou ausente ou não sublinhado não escapa aos códigos de entidade HTML como mostrado em: w3schools.com/tags/ref_entities.asp
Jason Axelson
6
O erro no github foi fechado como "Não será corrigido"; isso significa que esta solução não funciona e não funcionará.
Igor Chubin
3
Você diz que os " métodos escapeeunescape sublinhados ... não são seguros para a entrada do usuário" . O que você quer dizer com isso? Parece bobagem para mim, mas talvez eu esteja perdendo alguma coisa - você pode esclarecer?
Mark Amery
2
@VyvIT tentou _.unescape("&lt;img src=fake onerror=alert('boo!')&gt;")(no Chrome / FF / IE). Mas não apareceu nenhum alerta. Tentei no console e coloquei no meu arquivo JS também. Mesmo resultado.
Vivek Athalye
28

Eu acho que você está confundindo os métodos de texto e HTML. Veja este exemplo: se você usar o HTML interno de um elemento como texto, receberá tags HTML decodificadas (segundo botão). Mas se você usá-los como HTML, obterá a visualização formatada em HTML (primeiro botão).

<div id="myDiv">
    here is a <b>HTML</b> content.
</div>
<br />
<input value="Write as HTML" type="button" onclick="javascript:$('#resultDiv').html($('#myDiv').html());" />
&nbsp;&nbsp;
<input value="Write as Text" type="button" onclick="javascript:$('#resultDiv').text($('#myDiv').html());" />
<br /><br />
<div id="resultDiv">
    Results here !
</div>

Primeiro botão escreve: aqui está um conteúdo HTML .

O segundo botão grava: aqui está um conteúdo em <B> HTML </B>.

A propósito, você pode ver um plug-in que encontrei no plugin jQuery - o HTML decodifica e codifica que codifica e decodifica as strings HTML.

Canavar
fonte
26

A questão é limitada por 'with jQuery', mas pode ser útil saber que o código jQuery fornecido na melhor resposta aqui faz o seguinte abaixo ... isso funciona com ou sem o jQuery:

function decodeEntities(input) {
  var y = document.createElement('textarea');
  y.innerHTML = input;
  return y.value;
}
Rondó
fonte
20

Você pode usar a biblioteca he , disponível em https://github.com/mathiasbynens/he

Exemplo:

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

Eu desafiei o autor da biblioteca sobre a questão de saber se havia alguma razão para usar essa biblioteca no código do lado do cliente em favor do <textarea>hack fornecido em outras respostas aqui e em outros lugares. Ele forneceu algumas justificativas possíveis:

  • Se você estiver usando o node.js.servidor, o uso de uma biblioteca para codificação / decodificação HTML fornece uma solução única que funciona tanto do lado do cliente quanto do lado do servidor.

  • Alguns algoritmos de decodificação de entidade dos navegadores possuem bugs ou faltam suporte para algumas referências de caracteres nomeadas . Por exemplo, o Internet Explorer decodificará e renderizará espaços não-quebráveis ​​( &nbsp;) corretamente, mas os reportará como espaços comuns, em vez de espaços não-quebráveis, através da innerTextpropriedade de um elemento DOM , interrompendo o <textarea>hack (embora apenas em menor grau). Além disso, o IE 8 e 9 simplesmente não suportam qualquer uma das novas referências personagem chamado adicionados em HTML 5. O autor que também abriga um teste de apoio de referência personagem chamado pelo http://mathias.html5.org/tests/html / referências de caracteres nomeados / . No IE 8, ele relata mais de mil erros.

    Se você deseja se isolar dos bugs do navegador relacionados à decodificação de entidade e / ou conseguir lidar com toda a gama de referências de caracteres nomeados, não pode se safar do <textarea>hack; você precisará de uma biblioteca como ele .

  • Ele simplesmente parece que fazer as coisas dessa maneira é menos invasivo.

Mark Amery
fonte
4
+1 jQuery não é a solução para tudo. Use a ferramenta certa para o trabalho.
Mathias Bynens
Essa é a melhor maneira de decodificar entidades HTML. Todas as outras respostas (sobre essa e outras perguntas semelhantes) usam innerHTML (crie um novo elemento HTML, processe o código HTML e obtenha o innerHTML desse elemento, isso pode ser vulnerável a ataques XSS se você não for MUITO cuidadoso, veja mais ), ou eles sugerir o uso dos métodos Underscore.js unescape ou Lodash unescape , que estão incompletos (funciona apenas para poucas entidades HTML). A biblioteca he é a opção mais completa e segura!
ands
18

codificar:

$("<textarea/>").html('<a>').html();      // return '&lt;a&gt'

decodificar:

$("<textarea/>").html('&lt;a&gt').val()   // return '<a>'
user4064396
fonte
3
já existe uma resposta que funciona e é quase idêntica a isso. Não precisamos de respostas duplicadas
markasoftware
4
Esta é a resposta válida. A resposta de tom usa um elemento DIV, o que torna a resposta vulnerável ao XSS.
Francisco Hodge
2
Esta é a melhor resposta para maior clareza.
Dan Randolph
4

Usar

myString = myString.replace( /\&amp;/g, '&' );

É mais fácil fazê-lo no lado do servidor porque, aparentemente, o JavaScript não possui uma biblioteca nativa para lidar com entidades, nem encontrei nenhum próximo do topo dos resultados de pesquisa para as várias estruturas que estendem o JavaScript.

Procure por "entidades HTML JavaScript" e poderá encontrar algumas bibliotecas para esse fim, mas provavelmente todas elas serão construídas com base na lógica acima - substitua entidade por entidade.

Peter Mortensen
fonte
0

Eu só precisava ter um caractere de entidade HTML (⇓) como valor para um botão HTML. O código HTML parece bom desde o início no navegador:

<input type="button" value="Embed & Share  &dArr;" id="share_button" />

Agora eu estava adicionando uma alternância que também deveria exibir o caractere. Esta é a minha solução

$("#share_button").toggle(
    function(){
        $("#share").slideDown();
        $(this).attr("value", "Embed & Share " + $("<div>").html("&uArr;").text());
    }

Isso exibe ⇓ novamente no botão. Espero que isso ajude alguém.

philipp
fonte
O mais simples seria usar uma sequência de escape unicode (ou seja "Embed & Share \u21d1"), ou melhor ainda, "Embed & Share ⇑"se você puder servir seu script em UTF-8 (ou UTF-16, ou qualquer outra codificação que suporte o caractere)). Usar um elemento DOM para analisar uma entidade HTML apenas para transformar um caractere unicode arbitrário em uma string JavaScript é uma abordagem astuta e criativa que deixaria Rube Goldberg orgulhoso, mas não é uma boa prática; escapes unicode estão no idioma especificamente para lidar com este caso de uso.
Mark Amery
0

Você precisa criar uma função personalizada para entidades html:

function htmlEntities(str) {
return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g,'&gt;').replace(/"/g, '&quot;');
}
Todos
fonte
Eu não tenho idéia, isso me ajudou a marcar +1)
Szymon Toda
possivelmente foi recusado porque lida apenas com algumas entidades.
Jasen 11/01
A pergunta original era como decodificar entidades - isso faz o oposto do que é desejado; ele codifica um conjunto extremamente limitado de caracteres em entidades. Como a dica de ferramenta de voto negativo diz: "Esta resposta não é útil". Estou surpreso que, após 4 anos, ele ainda tenha uma pontuação líquida positiva.
Stephen P
0

Suponha que você tenha abaixo de String.

Nossas cabines Deluxe são aconchegantes, aconchegantes e amplificadas; confortável

var str = $("p").text(); // get the text from <p> tag
$('p').html(str).text();  // Now,decode html entities in your variable i.e 

str e atribuir de volta a

tag.

é isso aí.

Anirudh Sood
fonte
0

Para usuários do ExtJS, se você já possui a cadeia codificada, por exemplo, quando o valor retornado de uma função de biblioteca é o conteúdo innerHTML, considere esta função ExtJS:

Ext.util.Format.htmlDecode(innerHtmlContent)
Ilan
fonte
Isso funcionará apenas para 5 entidades HTML. Você pode ver isso na documentação e no código fonte .
ands
0

Estenda uma classe String:

String::decode = ->
  $('<textarea />').html(this).text()

e use como método:

"&lt;img src='myimage.jpg'&gt;".decode()
Sergio Belevskij
fonte
0

Tente o seguinte:

var htmlEntities = "&lt;script&gt;alert('hello');&lt;/script&gt;";
var htmlDecode =$.parseHTML(htmlEntities)[0]['wholeText'];
console.log(htmlDecode);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

parseHTML é uma função na biblioteca Jquery e retornará uma matriz que inclui alguns detalhes sobre a String fornecida.

em alguns casos, a String está sendo grande; portanto, a função separará o conteúdo em muitos índices.

e para obter todos os dados dos índices, você deve ir a qualquer índice e acessar o índice chamado "wholeText".

Eu escolhi o índice 0 porque ele funcionará em todos os casos (String pequena ou string grande).

Fawaz Al Romy
fonte
Embora esse snippet de código possa ser a solução, incluir uma explicação realmente ajuda a melhorar a qualidade da sua postagem. Lembre-se de que você está respondendo à pergunta dos leitores no futuro e essas pessoas podem não saber os motivos da sua sugestão de código.
26419 Johan Johan
O explicar é adicionado ... Obrigado :)
Fawaz Al Romy
-1

Ainda há um problema: a seqüência de caracteres escapada não parece legível quando atribuída ao valor de entrada

var string = _.escape("<img src=fake onerror=alert('boo!')>");
$('input').val(string);

Exapmle: https://jsfiddle.net/kjpdwmqa/3/

Lauris Kuznecovs
fonte
Esta não é uma resposta para a pergunta. O OP pede para decodificar (desescapular) a entidade HTML, mas nesta resposta você está usando o escapemétodo Underscore.js. Também não há explicação de como seu exemplo de código deve resolver o problema do OP.
ands
-1

Como alternativa, há também uma biblioteca para isso.

aqui, https://cdnjs.com/libraries/he

npm install he                 //using node.js

<script src="js/he.js"></script>  //or from your javascript directory

O uso é o seguinte ...

//to encode text 
he.encode('© Ande & Nonso® Company LImited 2018');  

//to decode the 
he.decode('&copy; Ande &amp; Nonso&reg; Company Limited 2018');

Felicidades.

Ande Caleb
fonte
Já existe uma resposta sobre a biblioteca que está completa, com um exemplo de código simples e uma boa explicação sobre por que e quando você deve usar a biblioteca .
ands
-3

Para decodificar entidades HTML com jQuery, basta usar esta função:

function html_entity_decode(txt){
    var randomID = Math.floor((Math.random()*100000)+1);
    $('body').append('<div id="random'+randomID+'"></div>');
    $('#random'+randomID).html(txt);
    var entity_decoded = $('#random'+randomID).html();
    $('#random'+randomID).remove();
    return entity_decoded;
}

Como usar:

Javascript:

var txtEncoded = "&aacute; &eacute; &iacute; &oacute; &uacute;";
$('#some-id').val(html_entity_decode(txtEncoded));

HTML:

<input id="some-id" type="text" />
Fred
fonte
-3

A maneira mais fácil é definir um seletor de classe para seus elementos e usar o seguinte código:

$(function(){
    $('.classSelector').each(function(a, b){
        $(b).html($(b).text());
    });
});

Nada mais necessário!

Eu tive esse problema e encontrei esta solução clara e funciona bem.

Hamidreza
fonte
Esta não é uma resposta à pergunta do OP. O OP pede para decodificar entidades HTML em STRING, não apenas isso não resolve o problema do OP, mas também substitui entidades HTML escapadas no elemento HTML por entidades não-capturadas que não devem ser feitas.
ands
-3

Eu acho que é exatamente o oposto da solução escolhida.

var decoded = $("<div/>").text(encodedStr).html();
Pedro
fonte