Puoi usare una virgola finale in un oggetto JSON?


392

Quando si genera manualmente un oggetto o un array JSON, è spesso più facile lasciare una virgola finale sull'ultimo elemento nell'oggetto o nell'array. Ad esempio, il codice per l'output da una matrice di stringhe potrebbe apparire (in uno pseudocodice come C ++):

s.append("[");
for (i = 0; i < 5; ++i) {
    s.appendF("\"%d\",", i);
}
s.append("]");

dandoti una stringa come

[0,1,2,3,4,5,]

È permesso?


66
Era qualcosa di cui avevo bisogno di cercare sul web qualche giorno fa. Non ho visto una risposta qui su SO, quindi nel seguire la missione del sito, ho posto la domanda e ho risposto in modo che altri potessero trovarla. Questo è qualcosa che Jeff ha esplicitamente dichiarato di voler fare qui.
Ben Combee,

5
Come ha detto Jeff, penso che vada benissimo usare SO come un 'taccuino' di cose che hai dovuto passare un po 'di tempo a cercare. Certo, questo è alla fine semplice di questi tipi di elementi, ma penso ancora che sia appropriato, soprattutto perché diversi motori javascript gestiranno questo in modo diverso.
pkaeding,

6
Mi chiedevo anche questo, quindi è una domanda perfettamente ragionevole.
hoju,

48
Per tutte quelle stronze a cui qualcuno ha fatto una semplice domanda, per favore arretrati. Questo è stato uno dei primi successi su Google e mi ha aiutato a consultare rapidamente la risposta. Grazie OP.

40
È interessante (o terrificante) in IE 8 che ho appena scoperto che alert([1, 2, 3, ].length)visualizzerà "4".
Daniel Earwicker

Risposte:


250

Purtroppo la specifica JSON non consente una virgola finale. Ci sono alcuni browser che lo permetteranno, ma generalmente devi preoccuparti di tutti i browser.

In generale, provo a risolvere il problema e aggiungo la virgola prima del valore effettivo, quindi si finisce con un codice simile al seguente:

s.append("[");
for (i = 0; i < 5; ++i) {
  if (i) s.append(","); // add the comma only if this isn't the first entry
  s.appendF("\"%d\"", i);
}
s.append("]");

Quella riga di codice in più nel tuo ciclo for non è quasi costosa ...

Un'altra alternativa che ho usato quando ho emesso una struttura su JSON da un dizionario di qualche forma è quella di aggiungere sempre una virgola dopo ogni voce (come stai facendo sopra) e quindi aggiungere una voce fittizia alla fine che non ha virgola finale (ma che è solo pigro; ->).

Purtroppo non funziona bene con un array.


2
Ho iniziato a utilizzare questa formattazione in tutto il mio codice JS (virgola prima dell'elemento sulla stessa riga) proprio per questo motivo. Rende le virgole finali extra molto più facili da individuare e consente di risparmiare molto tempo. È fastidioso, vorrei che ci fosse un'opzione per lanciare un errore per questo con Firefox (poiché ciò aiuterebbe con il debug).
rocketmonkeys,

47
È davvero un peccato che ECMA5 specifichi i rimorchi, ma JSON no.
FlavorScape

4
Sì, quella linea extra non è molto costosa, ma comunque fastidiosa.
René Nyffenegger,

2
Questo approccio funziona per i cicli for indicizzati. Che ne dici di ... in loop di stile? C'è un modo elegante?
kgf3JfUtW,

2
Quella riga di codice aggiuntiva può essere complicata quando si ha a che fare con le proprietà. Potresti scoprire di avere tonnellate di ifs solo per evitare quella stupida virgola. Per quanto riguarda il costoso YMMV, vedi questo ad esempio jsfiddle.net/oriadam/mywL9384 Chiarimento: la tua soluzione è fantastica, odio solo le specifiche che vietano una virgola finale.
Oriadam,

133

No. Le specifiche JSON, come mantenute su http://json.org , non consentono le virgole finali. Da quello che ho visto, alcuni parser potrebbero permetterli silenziosamente durante la lettura di una stringa JSON, mentre altri genereranno errori. Per l'interoperabilità, non dovresti includerlo.

Il codice sopra potrebbe essere ristrutturato, sia per rimuovere la virgola finale quando si aggiunge il terminatore di matrice o per aggiungere la virgola prima degli elementi, saltando quella per la prima.


1
ECMA 262 Sembra definirlo nella sezione 11.1.5 Inizializzatore di oggetti. Se questo è buono o no, sembra essere nelle specifiche.
Zero distrazione

6
Essere ECMAScript valido non significa necessariamente che un documento sia valido JSON - JSON è generalmente definito in RFC 4627 e tale specifica non consente la virgola finale.
Tim Gilbert,

1
@ZeroDistraction: ECMA262 definisce ECMAscript (noto anche come javascript) che è un linguaggio di programmazione come Perl o Ruby o C ++ o Java. JSON è un formato di dati come XML o CSV o YAML. Non sono la stessa cosa. JSON non esiste in EXMA262 ma la sintassi da cui deriva e si chiama Notazione letterale dell'oggetto (ON in JSON).
slebetman,

106

Semplice, economico, facile da leggere e funziona sempre indipendentemente dalle specifiche.

$delimiter = '';
for ....  {
    print $delimiter.$whatever
    $delimiter = ',';
}

L'assegnazione ridondante a $ delim è un prezzo molto piccolo da pagare. Funziona altrettanto bene se non esiste un ciclo esplicito ma frammenti di codice separati.


1
Questo è ciò che faccio in genere in situazioni come questa; Ritengo che l'assegnazione aggiuntiva sia più che compensata eliminando il condizionale necessario per aggiungere la virgola prima del valore nell'approccio alternativo ( stackoverflow.com/a/201856/8946 ).
Lawrence Dol,

5
Non mi piace questa soluzione, in quanto esiste un'altra variabile che inquina il mio ambito. Uno ifè più facile da capire. Ma grazie per averlo condiviso.
Ich,

3
Inoltre, è meglio contenere l'ambito del separatore:for(let ..., sep=""; ... ; sep=",") { ...
Lawrence Dol

1
Mi piace questo approccio perché evita i condizionali, anche se le moderne CPU hanno una buona logica di previsione dei rami. Vedi anche Perché è più veloce elaborare un array ordinato rispetto a un array non ordinato?
Hossein,

21

Le virgole finali sono consentite in JavaScript, ma non funzionano in IE. Le specifiche JSON senza versione di Douglas Crockford non le consentivano, e poiché era senza versione questo non avrebbe dovuto cambiare. Le specifiche JSON ES5 le consentivano come estensione, ma RFC 4627 di Crockford non lo fece e ES5 tornò a non consentirle. Firefox ha seguito l'esempio. Internet Explorer è il motivo per cui non possiamo avere cose carine.


1
Li ho appena provati in IE 11 senza alcun problema. In quali versioni di IE hai provato, dove li hai trovati a causare problemi?
iconoclasta,

10
Sembra che Crockford sia il motivo per cui non possiamo avere cose carine. Questo e commenti in JSON
Hejazzman,

Perché menzionare i browser Web quando l'OP utilizzava C ++ come pseudocodice? È improbabile che la domanda dell'OP sia correlata a browser Web o JavaScript.
cowlinator

@cowlinator J ava S cripta O bject N flottazione
forresthopkinsa

1
I letterali di oggetti Javascript hanno ispirato il formato, ma JSON non è per i motori Javascript
cowlinator il

13

Come è già stato detto, le specifiche JSON (basate su ECMAScript 3) non consentono la virgola finale. ES> = 5 lo consente, quindi puoi effettivamente usare quella notazione in JS puro. È stato discusso e alcuni parser lo hanno supportato ( http://bolinfest.com/essays/json.html , http://whereswalden.com/2010/09/08/spidermonkey-json-change-trailing-commas- non più accettato / ), ma è il fatto specifico (come mostrato su http://json.org/ ) che esso dovrebbe funzionare in JSON. Quella cosa ha detto ...

... Mi chiedo perché nessuno abbia sottolineato che puoi effettivamente dividere il ciclo alla 0a iterazione e utilizzare principale virgola invece di ultimi uno a sbarazzarsi del codice di confronto odore e qualsiasi sovraccarico delle prestazioni effettive nel circuito, con conseguente un codice che in realtà è più breve, più semplice e più veloce (a causa della mancanza di diramazioni / condizionali nel loop) rispetto ad altre soluzioni proposte.

Ad esempio (in uno pseudocodice in stile C simile al codice proposto dall'OP):

s.append("[");
// MAX == 5 here. if it's constant, you can inline it below and get rid of the comparison
if ( MAX > 0 ) {
    s.appendF("\"%d\"", 0); // 0-th iteration
    for( int i = 1; i < MAX; ++i ) {
        s.appendF(",\"%d\"", i); // i-th iteration
    }
}
s.append("]");

3
Esempio di codice semplice e veloce. Molto meglio delle soluzioni proposte da altre risposte.
Trevor Jex,

12

I programmatori PHP potrebbero voler dare un'occhiata implode () . Questo richiede un array che lo unisce usando una stringa.

Dai documenti ...

$array = array('lastname', 'email', 'phone');
echo implode(",", $array); // lastname,email,phone

2
Allo stesso modo, JavaScript ha join () . La maggior parte delle lingue ha un metodo simile o uno simile può essere facilmente codificato.
Dan Burton,

16
PHP ha json_encode, che gestisce tutti i dettagli della creazione di JSON, non solo delle virgole.
Brilliand,

Questo è figo! Come si applica a JSON e in che modo aiuta l'OP in una risoluzione alla loro domanda? Ricorda, "Puoi usare una virgola finale in un oggetto JSON?" è la domanda.
Rockin4Life33

7

È interessante notare che sia C & C ++ (e credo C #, ma non ne sono sicuro) consentono specificamente la virgola finale - esattamente per il motivo indicato: Rende molto più semplice la generazione programmatica di liste. Non sono sicuro del motivo per cui JavaScript non ha seguito il loro esempio.


13
L'ECMA ha esplicitamente specificato che le virgole finali sono consentite nelle specifiche imminenti: ejohn.org/blog/bug-fixes-in-javascript-2 Ancora un altro motivo per chiarire che JSON! = Oggetto JS.
mancanza di palpebre

PHP lo consente anche. Penso che sia l'unica caratteristica di PHP che mi piace. ; p
iconoclasta,

4

Usa JSON5. Non usare JSON.

  • Gli oggetti e le matrici possono avere virgole finali
  • Le chiavi oggetto possono essere non quotate se sono identificatori validi
  • Le stringhe possono essere a virgoletta singola
  • Le stringhe possono essere suddivise su più righe
  • I numeri possono essere esadecimali (base 16)
  • I numeri possono iniziare o terminare con un punto decimale (iniziale o finale).
  • I numeri possono includere Infinito e -Infinito.
  • I numeri possono iniziare con un segno più (+) esplicito.
  • Sono consentiti commenti sia inline (a riga singola) sia a blocchi (a più righe).

http://json5.org/

https://github.com/aseemk/json5


Sembra carino, ma non aggiungere nuovi tipi di dati sembra un'opportunità persa ... ovviamente il desiderio di rimanere un sottoinsieme rigoroso di ECMAScript 5 impone che, ma comunque ...
iconoclasta

1
Inoltre, le stringhe di mutlilina sono terribili. Sogno le multilinea ES6.
Marco Sulla

10
No, questo è un consiglio ORRIBILE. Di tutte le librerie JSON esistenti, pochissime supportano tale estensione; e tutto questo per "miglioramenti" molto discutibili. Si prega di NON causare ulteriore erosione dell'interoperabilità da parte di nuove estensioni fasulle come questa.
StaxMan,

8
Credo che passare la vita a sistemare le virgole sia più orribile.
user619271

3

C'è un modo possibile per evitare un if-branch nel loop.

s.append("[ "); // there is a space after the left bracket
for (i = 0; i < 5; ++i) {
  s.appendF("\"%d\",", i); // always add comma
}
s.back() = ']'; // modify last comma (or the space) to right bracket

2

Secondo le specifiche della classe JSONArray :

  • Un extra, (virgola) può apparire poco prima della parentesi di chiusura.
  • Il valore null verrà inserito quando c'è, (virgola) elision.

Quindi, a quanto ho capito, dovrebbe essere permesso di scrivere:

[0,1,2,3,4,5,]

Ma potrebbe accadere che alcuni parser restituiscano il 7 come numero di oggetti (come IE8 come ha sottolineato Daniel Earwicker) invece dei 6 previsti.


Modificato:

Ho trovato questo JSON Validator che convalida una stringa JSON su RFC 4627 (il tipo di supporto application / json per Notazione oggetto JavaScript) e contro la specifica del linguaggio JavaScript. In realtà qui un array con una virgola finale è considerato valido solo per JavaScript e non per la specifica RFC 4627.

Tuttavia, nella specifica RFC 4627 si afferma che:

2.3. Array

Una struttura di matrice è rappresentata da parentesi quadre che circondano zero o più valori (o elementi). Gli elementi sono separati da virgole.

array = begin-array [ value *( value-separator value ) ] end-array

Per me questo è di nuovo un problema di interpretazione. Se scrivi che gli elementi sono separati da virgole (senza indicare qualcosa su casi speciali, come l'ultimo elemento), potrebbe essere compreso in entrambi i modi.

PS RFC 4627 non è uno standard (come esplicitamente dichiarato) ed è già obsoleto da RFC 7159 (che è uno standard proposto) RFC 7159


6
La regola grammaticale fornita è la più precisa possibile. Non c'è modo di avere un value-separatorsenza un valuediritto accanto ad esso. Anche il testo è molto specifico. La "separazione dei valori" può essere applicata solo se sono presenti più valori. Quindi, se hai due valori uno accanto all'altro, vengono separati usando una virgola. Se hai un valore (o se guardi solo il valore alla fine), non c'è separazione, quindi nessuna virgola.
Steffen Heil,

1

Dalla mia esperienza passata, ho scoperto che diversi browser gestiscono le virgole finali in JSON in modo diverso.

Sia Firefox che Chrome lo gestiscono bene. Ma IE (Tutte le versioni) sembra rompersi. Intendo davvero interrompere e smettere di leggere il resto della sceneggiatura.

Tenendo presente questo, e anche il fatto che è sempre bello scrivere codice conforme, suggerisco di dedicare lo sforzo extra di assicurarsi che non ci siano virgole finali.

:)


1

Conservo un conteggio corrente e lo confronto con un conteggio totale. Se il conteggio corrente è inferiore al conteggio totale, visualizzo la virgola.

Potrebbe non funzionare se non si dispone di un conteggio totale prima di eseguire la generazione JSON.

Inoltre, se utilizzi PHP 5.2.0 o versioni successive, puoi semplicemente formattare la tua risposta utilizzando l'API JSON integrata.


1

Con Relaxed JSON, puoi avere le virgole finali o semplicemente lasciarle fuori . Sono opzionali

Non è necessario che siano presenti virgole per analizzare un documento simile a JSON.

Dai un'occhiata alle specifiche JSON rilassate e vedrai quanto sono rumorose le specifiche JSON originali. Troppe virgole e virgolette ...

http://www.relaxedjson.org

Puoi anche provare il tuo esempio usando questo parser RJSON online e vederlo analizzare correttamente.

http://www.relaxedjson.org/docs/converter.html?source=%5B0%2C1%2C2%2C3%2C4%2C5%2C%5D


JSON rilassato non è JSON tecnicamente non applicabile.
user2864740

Puoi convertire rjson in e da json, quindi è totalmente applicabile. Molto facile aggiungerlo anche al tuo flusso di lavoro.
Steven Spungin,

Questo presuppone che i consumatori a valle comprendano questo non-JSON. La conversione in JSON valido richiederebbe la rimozione della virgola in entrambi i casi.
user2864740

OP utilizza una stringa per iniziare. La stringa può essere analizzata in base a un json objectutilizzo JSON.parseo mediante una libreria RJSON.parse. Concordo con te se la fonte fosse un oggetto, ma non è questo il caso qui. Non vedo dove nella domanda menziona downstreamaffatto consumare un oggetto o una stringa.
Steven Spungin,

"Quando si genera manualmente un oggetto o un array JSON , è spesso più semplice lasciare una virgola finale sull'ultimo elemento nell'oggetto o nell'array. È consentito [ in JSON ]?" - quindi, ancora: sebbene si tratti di un formato alternativo interessante, non è JSON e non è tecnicamente applicabile alla domanda su JSON . Non c'è nulla da "difendere": è una proposta Z per interrogare X.
user2864740

0

Di solito cerco sull'array e allego una virgola dopo ogni voce nella stringa. Dopo il ciclo, cancello di nuovo l'ultima virgola.

Forse non è il modo migliore, ma meno costoso di controllare ogni volta se è l'ultimo oggetto nel ciclo immagino.


0

Non è raccomandato, ma puoi comunque fare qualcosa del genere per analizzarlo.

jsonStr = '[0,1,2,3,4,5,]';
let data;
eval('data = ' + jsonStr);
console.log(data)


0

Poiché un ciclo for viene utilizzato per iterare su un array o una struttura dati iterabile simile, possiamo usare la lunghezza dell'array come mostrato,

awk -v header="FirstName,LastName,DOB" '
  BEGIN {
    FS = ",";
    print("[");
    columns = split(header, column_names, ",");
  }
  { print("  {");
    for (i = 1; i < columns; i++) {
      printf("    \"%s\":\"%s\",\n", column_names[i], $(i));
    }
    printf("    \"%s\":\"%s\"\n", column_names[i], $(i));
    print("  }");
  }
  END { print("]"); } ' datafile.txt

Con datafile.txt contenente,

 Angela,Baker,2010-05-23
 Betty,Crockett,1990-12-07
 David,Done,2003-10-31

0

Come detto non è permesso. Ma in JavaScript questo è:

var a = Array()
for(let i=1; i<=5; i++) {
    a.push(i)
}
var s = "[" + a.join(",") + "]"

(funziona bene su Firefox, Chrome, Edge, IE11 e senza let in IE9, 8, 7, 5)

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.