jQuery.parseJSON genera l'errore "JSON non valido" a causa della virgoletta singola con escape in JSON


202

Sto facendo richieste al mio server usando jQuery.post()e il mio server sta restituendo oggetti JSON (come { "var": "value", ... }). Tuttavia, se uno qualsiasi dei valori contiene una virgoletta singola (come il escape corretto \'), jQuery non riesce ad analizzare una stringa JSON altrimenti valida. Ecco un esempio di ciò che intendo ( fatto nella console di Chrome ):

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

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

È normale? Non c'è modo di passare correttamente una singola citazione tramite JSON?

Risposte:


325

Secondo il diagramma della macchina a stati sul sito Web JSON , sono consentiti solo caratteri a virgoletta doppia con escape, non virgolette singole. I caratteri a virgoletta singola non devono essere sottoposti a escape:

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


Aggiornamento - Ulteriori informazioni per coloro che sono interessati:


Douglas Crockford non specifica specificamente perché la specifica JSON non consente virgolette singole con escape nelle stringhe. Tuttavia, durante la sua discussione su JSON nell'Appendice E di JavaScript: The Good Parts , scrive:

Gli obiettivi di progettazione di JSON dovevano essere minimi, portatili, testuali e un sottoinsieme di JavaScript. Meno dobbiamo concordare per interagire, più facilmente possiamo interagire.

Quindi forse ha deciso di consentire la definizione delle stringhe usando solo virgolette poiché questa è una regola in meno su cui tutte le implementazioni JSON devono concordare. Di conseguenza, è impossibile che un singolo carattere tra virgolette all'interno di una stringa termini accidentalmente la stringa, poiché per definizione una stringa può essere terminata solo da un carattere tra virgolette doppie. Quindi non è necessario consentire l'escaping di un singolo carattere di virgoletta nella specifica formale.


Scavando un po 'più profondo, di Crockford org.json realizzazione di JSON per Java è più ammissibile e non consentire singoli caratteri di citazione:

I testi prodotti con i metodi toString sono rigorosamente conformi alle regole di sintassi JSON. I costruttori sono più indulgenti nei testi che accetteranno:

...

  • Le stringhe possono essere citate con '(virgoletta singola).

Ciò è confermato dal codice sorgente JSONTokener . Il nextStringmetodo accetta caratteri di virgoletta singola con escape e li tratta come caratteri di virgoletta doppia:

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

Nella parte superiore del metodo è presente un commento informativo:

Il formato JSON formale non consente le stringhe tra virgolette singole, ma è consentita un'implementazione per accettarle.

Quindi alcune implementazioni accettano virgolette singole, ma non dovresti fare affidamento su questo. Molte implementazioni popolari sono piuttosto restrittive in questo senso e rifiuteranno JSON che contiene stringhe tra virgolette singole e / o virgolette singole con escape.


Infine, per ricollegarlo alla domanda originale, jQuery.parseJSONprima tenta di utilizzare il parser JSON nativo del browser o una libreria caricata come json2.js ove applicabile (che su una nota a margine è la libreria su cui si basa la logica jQuery se JSONnon è definita) . Quindi jQuery può essere permissivo solo come l'implementazione sottostante:

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 );
},

Per quanto ne so, queste implementazioni aderiscono solo alla specifica JSON ufficiale e non accettano virgolette singole, quindi nemmeno jQuery.


4
AGGIORNAMENTO :: JQuery è molto restrittivo quando si passa a JSON. Se provi l'avviso ($. ParseJSON ("[\" Ciao \\ '\ "]")); non funziona a causa di quanto riportato da Justin
daitangio il

2
" L'implementazione di JSON per Java di org.json di Crockford è più ammissibile e consente caratteri a virgoletta singola " # È solo una buona pratica: principio di robustezza
Duncan Jones,

1
@DuncanJones - Questo articolo potrebbe fornire informazioni sul perché nessuno dei browser sembra seguire questo principio per quanto riguarda JSON: joelonsoftware.com/items/2008/03/17.html
Justin Ethier,

1
@JustinEthier come sottolineato da questa risposta stackoverflow.com/a/25491642/759452 , il JSON spec tools.ietf.org/html/rfc7159 dice Any character may be escaped, questo può spiegare perché alcuni implementazione permetterebbe virgolette singole da sfuggiti.
Adrien,

1
@AdrienBe - Interessante ... ma intendevano dire che qualsiasi personaggio può essere evaso se è composto da 4 cifre esadecimali? Secondo sia il diagramma di stato sopra che quello nella sezione 7 della RFC, la fuga di una singola citazione come scritta non \'è ancora consentita. Sarebbe bello se la RFC fosse più esplicita su questo punto.
Justin Ethier,

15

Se hai bisogno di una virgoletta singola all'interno di una stringa, poiché \ 'non è definito dalle specifiche, usa \u0027 vedi http://www.utf8-chartable.de/ per tutte

modifica: per favore scusa il mio uso improprio della parola backtick nei commenti. Intendevo una barra rovesciata. Il mio punto qui è che nel caso in cui ci siano stringhe nidificate all'interno di altre stringhe, penso che possa essere più utile e leggibile usare unicode invece di molte barre rovesciate per sfuggire a una singola citazione. Se non sei nidificato, tuttavia, è davvero più semplice inserire semplicemente una vecchia citazione.


29
No. Usa solo una semplice citazione.
Jeff Kaufman,

A volte, è semplicemente più facile usare unicode di tonnellate di back-tick. Soprattutto quando si alternano zecche alternate.
slf,

3
Perché avresti bisogno di backtick? Se hai una stringa come "foo 'bar", allora lascia le singole virgolette senza caratteri di escape.
Jeff Kaufman,

3
esattamente quello che stavo cercando. Sto cercando di scrivere una stringa json su una pagina come una stringa js var e racchiuderla tra virgolette singole e terminava presto ogni volta che un valore di proprietà conteneva una virgoletta singola. Ora faccio solo un codice json.Replace ("'", "\ u0027") prima di scriverlo sulla pagina.
Zack,

@Zack Non dovresti racchiudere JSON tra virgolette. Se hai bisogno di una stringa da una stringa JSON esistente, devi solo stringerla di nuovo. in PHP, questo sarebbe var jsonEncodedAsString = <?= json_encode(myEncodedJson) ?>dove myEncodedJsonè il risultato di un precedente json_encodeche si occuperà di sfuggire alla tua virgoletta singola, in realtà, produrrà solo una grande stringa racchiusa tra virgolette doppie, quindi le virgolette singole non saranno sfuggite, ma le virgolette doppie volere.
Juan Mendes,

5

Capisco dove si trova il problema e quando guardo le specifiche è chiaro che le virgolette singole senza caratteri di escape devono essere analizzate correttamente.

Sto usando la funzione jQuery.parseJSON di jquery per analizzare la stringa JSON ma sto ancora ottenendo l'errore di analisi quando c'è una virgoletta singola nei dati che viene preparata con json_encode.

Potrebbe essere un errore nella mia implementazione che assomiglia a questo (PHP - lato server):

$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) . "]";

Il passaggio finale è che memorizzo la stringa codificata JSON in una variabile JS:

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

Se uso "" anziché "", viene comunque generato un errore.

SOLUZIONE:

L'unica cosa che ha funzionato per me è stato usare la maschera di bit JSON_HEX_APOS per convertire le virgolette singole in questo modo:

json_encode($tmp, JSON_HEX_APOS);

Esiste un altro modo di affrontare questo problema? Il mio codice è sbagliato o scritto male?

Grazie


'<= $ marcatore; ?> 'Questo non è valido JSON. Le virgolette circostanti vengono "mangiate" dall'interprete javascript, lasciando una stringa che inizia con un <... quello che volevi davvero provare era uno di questi: jQuery.parseJSON ('"<? = $ Marker;?>" '); jQuery.parseJSON ("\" <? = $ marker;?> \ ""); Secondo la specifica, le stringhe json devono usare virgolette doppie, ma a javascript non importa, quindi, hai una stringa javascript a virgoletta singola o una virgoletta doppia, ma se usi quest'ultima, devi scappare da tutte le usi di virgolette doppie all'interno della stringa.
Chris Cogdon,

3

Quando si invia una singola citazione in una query

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

Quando ottieni il valore includendo una singola citazione

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

Se si desidera cercare / inserire il valore che include una singola citazione in una query xxx=Replace(empid,"'","''")


1
Ma non è necessario sfuggire a una singola citazione quando la si passa come parte di una stringa JSON ...
Justin Ethier

2

Risolve un problema simile usando CakePHP per generare un blocco di script JavaScript usando il nativo di PHP json_encode. $contractorCompaniescontiene valori che hanno virgolette singole e come spiegato sopra e previsto json_encode($contractorCompanies)non li sfugge perché è JSON valido.

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

Aggiungendo addlash () attorno alla stringa codificata JSON si evitano quindi le virgolette che consentono a Cake / PHP di fare eco al javascript corretto nel browser. Gli errori JS scompaiono.

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

1

Stavo cercando di salvare un oggetto JSON da una richiesta XHR in un attributo data- * HTML5. Ho provato molte delle soluzioni precedenti senza successo.

Quello che alla fine ho fatto è stato sostituire la singola virgoletta 'con il suo codice &#39;usando un regex dopo che il metodo stringify () chiama il seguente modo:

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. Come stai generando il tuo JSON sul server? Stai usando una funzione di libreria (come json_encodein PHP) o stai costruendo la stringa JSON a mano?

L'unica cosa che attira la mia attenzione è l'apostrofo di fuga ( \'). Visto che stai usando virgolette doppie, come invece dovresti, non è necessario sfuggire alle virgolette singole. Non riesco a verificare se questa è effettivamente la causa del tuo errore jQuery, poiché non ho ancora aggiornato alla versione 1.4.1.


Uso una libreria in PHP per generare l'oggetto JSON - un po 'mancato scriverlo. Grazie per la segnalazione.
Erik Čerpnjak,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.