2013-06-12 8 views
8

Qualcuno potrebbe guidare come scrivere una classe che prenderebbe un dato JSON e cercherebbe di analizzarlo in una semplice lista di buffer da cui potremmo leggere i dati?Come scrivere una classe di analisi JSON di base

Es. JSON

{ name: 'John', age: 56 } 

..will essere analizzato in una tabella di coppie di valori chiave

name John 
age 56 

Come scrivere un metodo di analisi che contribuirebbe a creare un più veloce e più semplice?

Gentilmente non suggerire alcuna libreria esistente. Fornire un concetto per analizzare JSON.

+2

Perché non usi [Gson] (https://code.google.com/p/google-gson/)? –

+2

Questo NON è JSON valido! – fge

+2

[Cosa hai provato] (http://mattgemmell.com/2008/12/08/what-have-you-tried/) finora oltre a chiederci? –

risposta

18

Questo la risposta presuppone che tu voglia veramente scrivere un parser e sei pronto a fare lo sforzo richiesto.

È NECESSARIO iniziare con le specifiche formali di JSON. Ho trovato http://www.ietf.org/rfc/rfc4627.txt. Questo definisce la lingua con precisione. DEVI implementare tutto nelle specifiche e scrivere test per questo. Il parser DEVE gestire il JSON errato (come il tuo) e lanciare Eccezioni.

Se si desidera scrivere un parser, fermarsi, pensare e quindi non farlo. È molto lavoro per farlo funzionare correttamente. Qualunque cosa facciate, fatene un buon lavoro - i parser incompleti sono una minaccia e non dovrebbero mai essere distribuiti.

È NECESSARIO scrivere il codice conforme. Ecco alcune frasi dalla specifica. Se non li si capisce si deve la ricerca con attenzione e assicurarsi di aver compreso: "il testo JSON sono codificati in Unicode La codifica predefinita è UTF-8".

"Un parser JSON DEVE accettare tutti i testi conformi alla grammatica JSON ."

" Considerazioni sulla codifica: 8 bit se UTF-8; binario se UTF-16 o UTF-32

JSON may be represented using UTF-8, UTF-16, or UTF-32. When JSON 
    is written in UTF-8, JSON is 8bit compatible. When JSON is 
    written in UTF-16 or UTF-32, the binary content-transfer-encoding 
    must be used. 

"

" Qualsiasi carattere può essere sfuggito. Se il carattere è nella Base
Multilingual Plane (U + 0000 a U + FFFF), allora può essere
rappresentato come una sequenza di sei caratteri: un solidus inversa, seguita
dalla lettera minuscola u, seguita da quattro cifre esadecimali che
codificano il punto di codice del carattere. Le lettere esadecimali A anche se
F possono essere maiuscole o minuscole. Ad esempio, una stringa contenente
un solo carattere di solidus inverso può essere rappresentata come
"\ u005C". "

Se si capisce questo e ancora voglia di scrivere un parser, quindi rivedere alcuni altri parser, e vedere se qualcuno di loro hanno test di conformità. Prendere in prestito questi per la propria applicazione.

Se siete ancora dovresti prendere in seria considerazione l'utilizzo di un generatore di parser, ad esempio JAVACC, CUP e il mio strumento preferito, ANTLR. ANTLR è molto potente ma può essere difficile da iniziare.Vedi anche il suggerimento di Parboiled, che ora consiglierei. semplice e sarebbe un esercizio utile.La maggior parte dei parser-generatori generano un parser completo che può creare codice eseguibile o generare l'albero di analisi del tuo JSON

C'è un generatore di parser JSON che usa ANTLR allo http://www.antlr.org/wiki/display/ANTLR3/JSON+Interpreter se è permesso dare un'occhiata. Ho anche appena scoperto un Parboiled parser-generator for JSON. Se il motivo principale per cui scrivi un parser è imparare a farlo, questo è probabilmente un buon punto di partenza.

Se non è consentito (o non si desidera) utilizzare un generatore di parser, sarà necessario creare il proprio parser. Questo in genere si presenta in due parti:

un lexer/tokenizer. Questo riconosce le primitive di base definite nella specifica del linguaggio. In questo caso dovrebbe riconoscere parentesi graffe, virgolette, ecc. Probabilmente creerebbe anche la rappresentazione dei numeri.

un albero sintattico astratto (http://en.wikipedia.org/wiki/Abstract_syntax_tree, AST) generatore. Qui scrivi il codice per assemblare un albero che rappresenta l'astrazione del tuo JSON (ad esempio, gli spazi bianchi e le curse sono stati scartati).

Quando si dispone dell'AST, dovrebbe essere facile scorrere i nodi e creare l'output desiderato.

Ma scrivere generatori di parser, anche per un linguaggio semplice come JSON, è molto lavoro.

+0

ANTLR ha lo svantaggio che complica molto il processo di costruzione. Parboiled non ha tale svantaggio! Peccato che non sia abbastanza conosciuto. – fge

+0

@fge concordato. Darò un'occhiata. –

4

Se il tuo "JSON" è veramente così, dovresti prima prendere una mazza da baseball e andare a colpire il suo produttore in testa. Sul serio. (Perché?)

Se proprio insisti a scrivere la propria classe, è possibile ad esempio utilizzare un'interfaccia simile a questo:

public interface MyParser 
{ 
    boolean parse() 
     throws MyParsingException; 
    MyParser next(); 
} 

Implementazioni sarebbero poi prendere un CharBuffer come argomento e un costruttore mappa classe; e per analizzare fareste:

final CharBuffer buf = CharBuffer.wrap(yourSource); 
final MyMapBuilder builder = new MyMapBuilder(); 

MyParser parser = new OpenBracketParser(buf, builder); 

while (parser.parse()) 
    parser = parser.next(); 

// result is builer.build() 

Questo è solo un esempio ...

Seconda soluzione, che si desidera utilizzare uno strumento di analisi esistenti; in questo caso date un'occhiata a Parboiled. MOLTO più facile da usare rispetto a antlr, jflex o altri poiché si scrivono le tue grammatiche in puro Java.

Infine, se si decide che è troppo è troppo, e si decide di utilizzare una libreria JSON (si dovrebbe fare), andare con Jackson, che può leggere anche come JSON malformati:

public static void main(final String... args) 
    throws IOException 
{ 
    final ObjectMapper mapper = new ObjectMapper() 
     .configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true) 
     .configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); 

    final JsonNode node = mapper.readTree("{name: 'John'}"); 
    System.out.println(node); // {"name":"John"} 
} 
+0

Ha detto che non ci sono biblioteche. – BLaZuRE

+1

Uh ... Beh, a ciascuno il suo veleno, immagino ... – fge

0
public abstract class AbstractMessageObject { 
    public String toString() { 
    Gson gson = new Gson(); 
    //here mapping Object class name is prefixed to json message so otherwise knows the mapping object 
    return "^" + this.getClass().getName() + "^" + gson.toJson(this); 
    } 
} 

È possibile creare qualsiasi bean estendendo questo AbstractMessageObject. Ogni volta che si desidera analizzare quell'oggetto per json, è sufficiente chiamare il metodo toString

+1

OP specificato senza librerie :-( –

3

ne ho scritto uno prima.Passi:

  1. Prendere una stringa che rappresenta il testo JSON.

  2. Creare una classe JsonToken. Chiamo il mio Joken.

  3. Passare sopra l'intero testo dal passaggio 1 e analizzare il JToken (s).

  4. Raggruppa in modo ricorsivo e annida i tuoi JToken.

  5. Tentativo di mantenerlo semplice e uniforme. Tutti i nodi JToken hanno un array figlio che può avere 0 o più figli. Se il nodo è array, contrassegna come matrice. L'array figlio viene utilizzato per i figli del nodo se è un OBJECT o ARRAY. L'unica cosa che cambia è ciò che viene contrassegnato come. Mantieni anche tutti i valori come tipo di stringa. In questo modo hai solo bisogno di un singolo membro sul nodo chiamato "valore" che possa essere interpretato come il tipo di dati corretto dopo che tutto il lavoro è stato svolto.

  6. Utilizzare codifica difensiva e test di unità. Scrivi test per tutti i componenti del parser. È meglio spendere 3 ore in più per scrivere codice in modo paranoico, dove si presume che si commettano errori ogni secondo da dover trascorrere 3 ore a cacciare gli insetti. Codice abbastanza paranoico, e molto raramente passerai il tempo a essere frustrato durante il debug.

Esempio di codice: quando stavo facendo un (ironicamente) sfida sul code-eval.com facile. C'è stata una sfida parsing di menu json. Ho pensato che sarebbe stato ingannare lo per utilizzare qualsiasi funzione built-in, perché per me l'intero punto delle sfide del codice è di testare le tue capacità di risoluzione dei problemi dell'algoritmo. La sfida è qui: https://www.codeeval.com/open_challenges/102/

mio codice, che passa questa sfida, utilizzando un parser costruita da zero in javascript:

CODE: https://pastebin.com/BReK9iij 
Was not able to post it on stack-overflow because it is too much code. 
Put it in a non-expiring paste-bin post. 

Nota: questo codice potrebbe utilizzare qualche miglioramento. Alcuni di questi sono molto inefficienti e non funzioneranno con Unicode.

Non è consigliabile scrivere il proprio parser JSON a meno che non si stia interpretando il JSON in un modo non standard.

Ad esempio: attualmente sto usando JSONedit per organizzare i rami per un'avventura basata su testo. Sto solo utilizzando il formato file JSON perché è compatto e il visualizzatore mi consente di espandere e contrarre gli elementi. Il parser standard fornito con GOLang non interpreta le informazioni nel modo in cui io voglio che sia interpretato, quindi scrivo il mio parser.