jQuery.parseJSON lança erro "JSON inválido" devido a aspas simples escapadas em JSON


202

Estou fazendo solicitações ao meu servidor usando jQuery.post()e meu servidor está retornando objetos JSON (como { "var": "value", ... }). No entanto, se algum dos valores contiver uma única citação (como escapou corretamente \'), o jQuery falhará ao analisar uma sequência JSON válida, caso contrário. Aqui está um exemplo do que 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 cotação via JSON?

Respostas:


325

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

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


Atualização - Mais informações para aqueles que estão interessados:


Douglas Crockford não diz especificamente por que a especificação JSON não permite aspas simples escapadas dentro de strings. No entanto, durante sua discussão sobre JSON no Apêndice E do JavaScript: The Good Parts , ele escreve:

Os objetivos 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.

Portanto, talvez ele tenha decidido permitir apenas que cadeias sejam definidas usando aspas duplas, pois essa é uma regra a menos com a qual todas as implementações 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 profundo, do Crockford org.json implementação de JSON para Java é mais admissível e faz permitir caracteres de aspas simples:

Os textos produzidos pelos métodos toString estão em conformidade estrita com as regras de sintaxe JSON. Os construtores são mais tolerantes nos textos que aceitarão:

...

  • As strings podem ser citadas com '(aspas simples).

Isso é confirmado pelo código-fonte JSONTokener . O nextStringmétodo aceita caracteres de aspas simples escapados 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;
        ...

No topo do método, há um comentário informativo:

O formato JSON formal não permite seqüências de caracteres entre 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 nesse sentido e rejeitarão o JSON que contém seqüências de caracteres entre aspas simples e / ou aspas simples escapadas.


Finalmente, para vincular isso à pergunta original, jQuery.parseJSONprimeiro tente usar o analisador JSON nativo do navegador ou uma biblioteca carregada, como json2.js, quando aplicável (que em uma nota lateral é a biblioteca na qual a lógica do jQuery se baseia se JSONnão estiver definida) . Portanto, o jQuery 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 );
},

Tanto quanto sei, essas implementações seguem apenas a especificação JSON oficial e não aceitam aspas simples, portanto, o jQuery também não.


4
UPDATE :: JQuery é muito restritivo ao colar JSON. Se você tentar o alerta ($. ParseJSON ("[\" Ciao \\ '\ "]"))); ele não funciona por causa do que Justin informou
— daitangio

2
" Implementação org.json do Crockford de JSON para Java é mais admissível e não permite cotação caracteres simples " # isso é apenas boa prática: princípio robustez
— Duncan Jones

1
@DuncanJones - Este artigo pode fornecer uma visão sobre por que nenhum dos navegadores parecem seguir esse princípio em relação a JSON: joelonsoftware.com/items/2008/03/17.html
— Justin Ethier

1
@JustinEthier como apontado por esta resposta stackoverflow.com/a/25491642/759452 , o JSON especificação tools.ietf.org/html/rfc7159 diz Any character may be escaped, isso pode explicar por que alguns implementação permitiria aspas simples para ser escapado.
— Adrien Seja

1
@AdrienBe - Interessante ... mas eles significam que qualquer caractere pode ser escapado se consistir em 4 dígitos hexadecimais? De acordo com o diagrama de estados acima e o da seção 7 da RFC, \'ainda não é permitido o escape de uma única citação conforme escrita . Seria bom se o RFC fosse mais explícito nesse ponto.
— 23614 Justin Ethier

15

Se você precisa de uma aspa simples dentro de uma string, uma vez que \' é indefinido pela especificação, o uso \u0027 ver http://www.utf8-chartable.de/ para todos eles

edit: desculpe meu uso indevido da palavra backticks nos comentários. Eu quis dizer barra invertida. Meu argumento aqui é que, no caso de você ter aninhado cadeias dentro de outras cadeias, acho que pode ser mais útil e legível usar unicode em vez de muitas barras invertidas para escapar de uma única citação. Se você não estiver aninhado, no entanto, é realmente mais fácil colocar uma citação simples e antiga.


29
Não. Basta usar uma aspas simples.
— Jeff Kaufman

Às vezes, é muito mais fácil usar unicode do que toneladas de back-ticks. Particularmente quando dentro de back-ticks alternados.
— slf

3
Por que você precisaria de backticks? Se você tem uma string como "foo 'bar'", basta deixar as aspas simples sem escape.
— 21412 Jeff Kaufman

3
Exatamente o que eu estava procurando. Estou tentando escrever uma string json em uma página como uma string js var e coloque-a entre aspas simples e era finalizada mais cedo sempre que um valor de propriedade continha uma única citação. Agora eu apenas faço um json.Replace ("'", "\ u0027") no código antes de escrevê-lo na página.
— Zack

@ Zack Você não deve incluir JSON entre aspas. Se você precisar de uma sequência fora de uma sequência JSON existente, apenas a especifique novamente. em PHP, é var jsonEncodedAsString = <?= json_encode(myEncodedJson) ?>aí que myEncodedJsonestá o resultado de um anterior. json_encodeIsso resolverá o escape de sua aspas simples, na verdade, apenas produzirá algo em uma grande string envolta em aspas duplas, para que aspas simples não sejam escapadas, mas aspas duplas vai.
— Juan Mendes

5

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

Estou usando a função jQuery.parseJSON do jquery para analisar a string JSON, mas ainda obtendo o erro de análise quando há uma única citação nos dados preparados com json_encode.

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

$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 armazene a string codificada em JSON em uma variável JS:

<script type="text/javascript">
employees = jQuery.parseJSON('<?=$marker; ?>');
</script>

Se eu usar "" em vez de '', ele ainda gera um erro.

SOLUÇÃO:

A única coisa que funcionou para mim foi usar a máscara de bit JSON_HEX_APOS para converter aspas simples assim:

json_encode($tmp, JSON_HEX_APOS);

Existe outra maneira de resolver esse problema? Meu código está errado ou está mal escrito?

obrigado


'<? = $ marcador; ?> 'isso não é válido json. As aspas circundantes são "consumidas" pelo intérprete javascript, deixando uma string que começa com um <... o que você realmente queria tentar era um destes: jQuery.parseJSON ('"<? = $ Marker;?>" '); jQuery.parseJSON ("\" <? = $ marcador;?> \ ""); De acordo com a especificação, json strings deve usar aspas duplas, mas o javascript não se importa, portanto, você tem uma string javascript de aspas simples ou aspas duplas, mas se você usar a última, terá que escapar de todas as usos de aspas duplas dentro da string.
— precisa saber é o seguinte

3

Quando você está enviando uma aspas simples em uma consulta

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

Quando você obtém o valor, incluindo uma única citação

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

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


1
Mas não há necessidade de escapar de uma única citação ao passá-la como parte de uma string JSON ...
— Justin Ethier 15/03

2

Ocorreu um problema semelhante usando o CakePHP para gerar um bloco de script JavaScript usando o nativo do PHP json_encode. $contractorCompaniescontém valores que possuem aspas simples e, como explicado acima e o esperado json_encode($contractorCompanies), não os escapam porque seu JSON válido.

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

Adicionando addlashes () ao redor da string codificada em JSON, você escapa as aspas, permitindo que o Cake / PHP faça eco do javascript correto no navegador. Os erros do JS desaparecem.

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

1

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

O que finalmente acabei fazendo foi substituir a aspas simples 'pelo código &#39;usando um regex após o método stringify () chamar da seguinte maneira:

var productToString = JSON.stringify(productObject);
var quoteReplaced = productToString.replace(/'/g, "&#39;");
var anchor = '<a data-product=\'' + quoteReplaced + '\' href=\'#\'>' + productObject.name + '</a>';
// Here you can use the "anchor" variable to update your DOM element.

0

Interessante. Como você está gerando seu JSON no servidor final? Você está usando uma função de biblioteca (como json_encodeno PHP) ou está construindo a string JSON manualmente?

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


Eu uso uma biblioteca em PHP para gerar o objeto JSON - meio que perdi anotá-lo. Obrigado por apontar isso.
— Erik Čerpnjak 27/01
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.