2012-06-28 4 views
5

Ho un file JSON con molti elementi come questi:lettura più elementi da un file JSON

{ 
"code" : "hfuiew89", 
"type" : "location", 
"coordinates" : [ { "lat" : 40.9861, "lon" : 29.1046, "index" : 1 }, 
      { "lat" : 40.9976, "lon" : 29.1153, "index" : 2 }, 
      { "lat" : 40.9809, "lon" : 29.2194, "index" : 3 }] 
} 
{ 
"code" : "klsdsjh", 
"type" : "location", 
"relatedTags" : [ "kolmha" ], 
"coordinates" : [ { "lat" : 40.9808, "lon" : 29.1605, "index" : 1 }, 
       { "lat" : 40.9965, "lon" : 29.1672, "index" : 2 }] 
} 

voglio leggere quel file con GSON ma tutti gli esempi che ho trovato sono solo per un elemento. quindi dopo aver letto il primo, lancia l'eccezione 'EOF previsto'. come posso superare questo?

+2

JSON è destinata * * essere un unico soggetto (essere che un oggetto, o un array) - e quello che hai è più oggetti. Quello che vuoi veramente in questa situazione è un array al livello più alto, con ogni oggetto come elemento in esso. Puoi influenzare la * generazione * di questo JSON, o sei bloccato con questo formato? –

risposta

3

Greg ha ragione, questo è JSON errato, e dovresti provare a generare JSON valido, che è anteporre "[" all'inizio, append "]" alla fine e separare ogni elemento con una virgola (", "), in modo che sia un array JSON di oggetti JSON.

Tuttavia, se non è possibile modificare il formato che si possiede, considerarlo "una stringa contenente una concatenazione di frammenti JSON ben formati". Avvicinandoti in questo modo, spezza la grande stringa in stringhe json più piccole e valide e analizzale una ad una.

Per rompere la grande stringa in singoli frammenti è sufficiente contare le parentesi. Con un "pre-parser" che copia elementi in un buffer (un StringBuilder?), Incrementa un contatore ogni volta che incontra un "{", diminuisce ogni volta che enouter un "}" e se il contatore è a zero pass la stringa del buffer su gson per l'analisi, cancellare il buffer e andare alla fine del file.

Puoi anche usare quel pre-parser per convertirlo in json valido, semplicemente aggiungendo un "," quando il contatore raggiunge lo zero, e il passaggio di tutto a gson per un singolo parsing, ma ciò potrebbe significare caricare tutto in ram e non so quanto è grande il tuo file.

+0

Insieme a questo, puoi semplicemente creare il tuo file come una matrice di oggetti JSON. Tuttavia potresti incorrere in problemi di memoria se ci sono troppe entità nell'array.Altrimenti, una stringa separata di entità JSON è migliore e consente di caricare solo una parte del file alla volta. – Drizzt321

+0

Sì, questo è quello che stavo cercando di esprimere: un singolo file json grande e una sola chiamata per l'analisi, potrebbe sembrare più semplice, ma potrebbe anche significare caricare tutto in ram; mentre si procede "passo dopo passo" si può lasciare gestire le entità una per una ... questo è di nuovo SAX contro DOM, ma ora che è chiamato JSON lo fa sembrare molto più k00l. –

+0

Haha, così vero. Anche se JSON sembra meno prolisso (nessun tag di chiusura per esempio) e fornisce anche un mezzo molto semplice per passare i dati a Javascript, che è di gran moda in questi giorni e quindi probabilmente uno dei motivi della grande crescita di JSON. – Drizzt321

9

Per quel che vale ...

la seguente istruzione non è corretto. Gson non ha una funzione incorporata per gestire semplicemente la deserializzazione di tale sequenza JSON. (Vedere i commenti.)

Se l'opzione JSON-to/from-Java API è un'opzione, Jackson dispone di tale funzionalità, come illustrato di seguito.

input.json

{ 
"name":"A" 
} 
{ 
"name":"B" 
} 

JacksonFoo.java

import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY; 
import static com.fasterxml.jackson.annotation.PropertyAccessor.FIELD; 

import java.io.File; 
import java.util.Iterator; 

import com.fasterxml.jackson.databind.ObjectMapper; 

public class JacksonFoo 
{ 
    public static void main(String[] args) throws Exception 
    { 
    ObjectMapper mapper = new ObjectMapper().setVisibility(FIELD, ANY); 
    Iterator<Thing> thingsIterator = mapper.reader(Thing.class).readValues(new File("input.json")); 
    while (thingsIterator.hasNext()) 
    { 
     System.out.println(thingsIterator.next()); 
    } 
    } 
} 

class Thing 
{ 
    private String name; 

    @Override 
    public String toString() 
    { 
    return String.format("Thing: name=%s", name); 
    } 
} 

uscita:

Thing: name=A 
Thing: name=B 

Aggiornamento: Una soluzione simile che utilizza Gson.

GsonFoo.java

import java.io.FileReader; 

import com.google.gson.Gson; 
import com.google.gson.GsonBuilder; 
import com.google.gson.JsonStreamParser; 

public class GsonFoo 
{ 
    public static void main(String[] args) throws Exception 
    { 
    Gson gson = new GsonBuilder().create(); 

    JsonStreamParser parser = new JsonStreamParser(new FileReader("input.json")); 
    while(parser.hasNext()) 
    { 
     System.out.println(gson.fromJson(parser.next(), Thing.class)); 
    } 
    } 
} 
+2

Questo post non è corretto. Gson ha questa caratteristica (errata). Si chiama JsonStreamParser e la documentazione è qui: http://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/JsonStreamParser.html –

+0

Ah, pulito. Sono stato scagliato dall'uso della parola "Stream" nell'API GSON. Ho appena pensato che "Stream" si riferisse all'analisi di JSON su un token di streaming alla volta, a differenza dei dati JSON vincolanti su oggetti/array. –

+0

Aggiornamento della risposta di conseguenza. –