jQuery.parseJSON gera um erro “JSON inválido” devido a uma citação simples de escape no JSON

Estou fazendo pedidos para o meu servidor usando jQuery.post() e meu servidor está retornando objects JSON (como { "var": "value", ... } ). No entanto, se algum dos valores contiver uma aspa simples (apropriadamente com escape como \' ), o jQuery falhará ao analisar uma string JSON de outra forma válida. Aqui está um exemplo do que eu quero dizer ( feito no console do Chrome ):

 data = "{ \"status\": \"success\", \"newHtml\": \"Hello \\\'x\" }"; eval("x = " + data); // { newHtml: "Hello 'x", status: "success" } $.parseJSON(data); // Invalid JSON: { "status": "success", "newHtml": "Hello \'x" } 

Isso é normal? Não há como passar corretamente uma única citação via JSON?

De acordo com o diagrama de máquina de estado no site JSON , somente caracteres de aspas duplas são permitidos, não aspas simples. Caracteres de aspas simples não precisam ser escapados:

http://www.json.org/string.gif

Atualização – Mais informações para os interessados:


Douglas Crockford não diz especificamente porque a especificação JSON não permite citações simples com escape dentro de strings. No entanto, durante sua discussão sobre o JSON no Apêndice E de JavaScript: The Good Parts , ele escreve:

Os objectives de design do JSON eram mínimos, portáteis, textuais e um subconjunto de JavaScript. Quanto menos precisamos concordar para interoperar, mais facilmente podemos interoperar.

Então, talvez ele tenha decidido permitir apenas que as strings fossem definidas usando aspas duplas, já que essa é uma regra a menos que todas as implementações do JSON devem concordar. Como resultado, é impossível que um caractere de aspas simples dentro de uma string termine acidentalmente a string, porque, por definição, uma string só pode ser terminada por um caractere de aspas duplas. Portanto, não há necessidade de permitir o escape de um caractere de aspas simples na especificação formal.


Indo um pouco mais fundo, a implementação org.json do JSON for Java de Crockford é mais permissível e permite caracteres de aspas simples:

Os textos produzidos pelos methods toString estão em conformidade com as regras de syntax do JSON. Os construtores são mais tolerantes nos textos que aceitam:

  • Cordas podem ser citadas com ‘(aspas simples).

Isso é confirmado pelo código-fonte JSONTokener . O método nextString aceita caracteres de aspas simples com escape e os trata como caracteres de aspas duplas:

 public String nextString(char quote) throws JSONException { char c; StringBuffer sb = new StringBuffer(); for (;;) { c = next(); switch (c) { ... case '\\': c = this.next(); switch (c) { ... case '"': case '\'': case '\\': case '/': sb.append(c); break; ... 

Na parte superior do método, há um comentário informativo:

O formato JSON formal não permite strings em aspas simples, mas uma implementação pode aceitá-las.

Portanto, algumas implementações aceitarão aspas simples – mas você não deve confiar nisso. Muitas implementações populares são bastante restritivas a esse respeito e rejeitam o JSON que contém strings com aspas simples e / ou aspas simples com escape.


Finalmente, para vincular isso à pergunta original, o jQuery.parseJSON primeiro tenta usar o analisador JSON nativo do navegador ou uma biblioteca carregada, como json2.js, onde aplicável (o que, em uma nota lateral, é a biblioteca na qual a lógica jQuery é baseada se JSON não está definido). Assim, o jQuery só pode ser tão permissivo quanto a implementação subjacente:

 parseJSON: function( data ) { ... // Attempt to parse using the native JSON parser first if ( window.JSON && window.JSON.parse ) { return window.JSON.parse( data ); } ... jQuery.error( "Invalid JSON: " + data ); }, 

Até onde eu sei, essas implementações só aderem à especificação JSON oficial e não aceitam aspas simples, portanto, o jQuery também não.

Se você precisar de uma aspa simples dentro de uma string, já que \ ‘é indefinido pela especificação, use \u0027 veja http://www.utf8-chartable.de/ para todos eles

Editar: por favor, desculpe o uso indevido da palavra backticks nos comentários. Eu quis dizer barra invertida. Meu ponto aqui é que, no caso de você aninhar strings dentro de outras strings, eu acho que pode ser mais útil e legível para usar unicode em vez de muitas barras invertidas para escaping de uma aspa simples. Se você não está nested no entanto, é realmente mais fácil apenas colocar uma citação simples e simples lá.

Eu entendo onde está o problema e quando olho para as especificações está claro que aspas simples sem escape devem ser analisadas corretamente.

Eu estou usando a function jquery`s jQuery.parseJSON para analisar a cadeia JSON, mas ainda recebendo o erro de análise quando há uma única aspas nos dados que são preparados com json_encode.

Poderia ser um erro na minha implementação que se parece com isso (lado do servidor PHP):

 $data = array(); $elem = array(); $elem['name'] = 'Erik'; $elem['position'] = 'PHP Programmer'; $data[] = json_encode($elem); $elem = array(); $elem['name'] = 'Carl'; $elem['position'] = 'C Programmer'; $data[] = json_encode($elem); $jsonString = "[" . implode(", ", $data) . "]"; 

A etapa final é que eu armazeno a string codificada JSON em uma variável JS:

  

Se eu usar “” em vez de “”, ainda gera um erro.

SOLUÇÃO:

A única coisa que funcionou para mim foi usar o bitmask JSON_HEX_APOS para converter aspas simples assim:

 json_encode($tmp, JSON_HEX_APOS); 

Existe outra maneira de abordar essa questão? Meu código está errado ou mal escrito?

obrigado

Quando você está enviando uma única cotação em uma consulta

 empid = " T'via" empid =escape(empid) 

Quando você recebe o valor, incluindo uma única cotação

 var xxx = request.QueryString("empid") xxx= unscape(xxx) 

Se você deseja pesquisar / inserir o valor que inclui uma aspa simples em uma consulta xxx=Replace(empid,"'","''")

Atingindo um problema semelhante usando o CakePHP para produzir um bloco de script JavaScript usando o json_encode nativo do PHP. $contractorCompanies contém valores que possuem aspas simples e, conforme explicado acima e esperado, json_encode($contractorCompanies) não os escapa por causa de seu JSON válido.

 < ?php $this->Html->scriptBlock("var contractorCompanies = jQuery.parseJSON( '".(json_encode($contractorCompanies)."' );"); ?> 

Ao adicionar addslashes () ao redor da string codificada JSON, você então escapa as aspas, permitindo que Cake / PHP faça o eco do JavaScript correto para o navegador. Erros JS desaparecem.

 < ?php $this->Html->scriptBlock("var contractorCompanies = jQuery.parseJSON( '".addslashes(json_encode($contractorCompanies))."' );"); ?> 

Interessante. Como você está gerando seu JSON no servidor? Você está usando uma function de biblioteca (como json_encode no PHP) ou está construindo a string JSON manualmente?

A única coisa que me chama a atenção é o escape apóstrofo ( \' ). Visto que você está usando aspas duplas, como de fato deveria, não há necessidade de escaping de aspas simples. Não consigo verificar se essa é realmente a causa do erro do jQuery, pois ainda não atualizei para a versão 1.4.1.

Eu estava tentando salvar um object JSON de uma solicitação XHR em um atributo data- * HTML5. Eu tentei muitas das soluções acima sem sucesso.

O que eu finalmente acabei fazendo foi replace a citação simples ' por código ' ' usando um regex após o método stringify () chamar da seguinte maneira:

 var productToString = JSON.stringify(productObject); var quoteReplaced = productToString.replace(/'/g, "'"); var anchor = '' + productObject.name + ''; // Here you can use the "anchor" variable to update your DOM element.