2013-05-03 11 views
5

ho a che fare con i sistemi che manipolano i dati JSON "rilassato", che comprende la linea di shell in stile # commenti:Processing commenti guscio in stile in JSON

[ 
    { 
    # Batman 
    "first-name": "Bruce", 
    "last-name": "Wayne" 
    }, 
    { 
    # Superman 
    "first-name": "Clark", 
    "last-name": "Kent" 
    } 
] 

La parte del sistema su cui sto lavorando usi json-lib - che sono sorpreso di scoprire è tollerante nei commenti stile shell - per analizzare l'input JSON.

ho bisogno di estrarre alcune annotazioni aggiuntive da tali osservazioni, ma JSON-lib sembra disfarsene appena senza fornire un'API per la loro lettura:

JSONObject map = (JSONObject)JSONSerializer.toJSON("{\n"+ 
                " # Batman\n" + // note the shell-style # comment 
                " \"first-name\": \"Bruce\",\n" + 
                " \"last-name\": \"Wayne\"\n" + 
                "}"); 
System.out.println(map.toString()); 
/* <<'OUTPUT' 
* {"first-name":"Bruce","last-name":"Wayne"} 
* OUTPUT 
* note the absence of the shell-style comment 
*/ 

Questo ha senso dal momento che i commenti non fanno parte del JSON spec e io sono fortunato che json-lib non si limita a soffocare quando li analizza in primo luogo.

Di nota:

  • altri sistemi consumano questo stesso JSON e le annotazioni devono essere trasparenti per loro, pertanto la struttura JSON non può essere modificato aggiungendo proprietà per i commenti invece.
  • non tutti i componenti e gli oggetti nel mio sistema hanno accesso all'origine JSON non elaborata: un componente legge il file e lo analizza utilizzando JSONlib e passa mappe de-serializzate ecc.

Come è possibile leggere e analizzare questi commenti durante l'elaborazione dell'ingresso JSON? C'è una libreria che mi permetterà di leggerli e collegarli alla loro posizione nel JSON - posso collegare facilmente il commento Batman alla voce "Bruce Wayne"?

Attualmente sto usando json-lib, ma sono aperto a indagare su altre librerie JSON e altrettanto aperto all'uso di altri linguaggi che estendono JSON, come YAML - ma non sono sicuro che quegli strumenti mi permetteranno di leggere ed elaborare i commenti nel mio input.

+0

http://www.lifl.fr/~riquetd/parse-a-json-file-with-comments.html Questo collegamento utilizza regex: ''(^)? [^ \ S \ n] */(?: \ * (. *?) \ */[^ \ S \ n] * |/[^ \ n] *) ($)? ''Per rimuovere i commenti. Naturalmente puoi usare la stessa espressione regolare per altri scopi. –

+0

@remyabel - Non tutti i componenti e gli oggetti nel mio sistema hanno accesso all'origine JSON non elaborata: un componente legge il file e lo analizza utilizzando JSONlib e passa mappe de-serializzate ecc. –

+2

potresti sempre non mettere dati significativi in ​​una posizione "buttare via"? proprio come non immagazzino le cose importanti nel bidone della spazzatura fuori da casa mia ... – jtahlborn

risposta

4

Quello che ho scelto di fare è modificare pubblico dominio biblioteca JSON.org per sostenere commenti shell e commenti aggiungendo al oggetto JSON, come ho fatto in questo GitHub gist:

https://gist.github.com/peteroupc/5529464

Esempio di utilizzo:

JSONObject obj=new JSONObject("{ # Comment\n"+ 
     "\"first-key\":\"first-value\",\n"+ 
     "\"second-key\":\"second-value\" }", 
     JSONObject.OPTION_SHELL_COMMENTS | // Support SHELL-style comments 
     JSONObject.OPTION_ADD_COMMENTS // Incorporate comments in the JSON object 
); 
System.out.println(obj); // Output the JSON object 

Esempio di output. Si noti che il commento si verifica in una chiave chiamata "@comment".

{"second-key":"second-value","@comment":"Comment","first-key":"first-value"} 

Ma una delle vostre esigenze è che "la struttura JSON non può essere modificato con l'aggiunta di proprietà per i commenti, invece." Ciò significa che i commenti devono essere associati agli oggetti JSON in qualche altro modo. Fortunatamente, una specifica chiamata JSON Pointer è stata recentemente pubblicata come come RFC 6901. JSON Pointer è una stringa che fa riferimento a un oggetto JSON all'interno di un altro oggetto JSON. Di conseguenza, sono necessari passaggi aggiuntivi: trovare gli oggetti figli con i tasti "@comment", rimuovere le chiavi e creare un mapping dei puntatori JSON ai commenti.

Ciò è illustrato dal seguente codice.

// Objects with comments associated with them will 
// now contain an "@comment" key; get the JSON Pointers 
// (RFC6901) to these objects and remove the "@comment" keys. 
Map<String,Object> pointers=JSONPointer.getPointersWithKeyAndRemove(obj,"@comment"); 
// For each JSON Pointer, get its corresponding object. 
// They will always be JSONObjects. 
for(String pointer : pointers.keySet()){ 
    JSONObject subobj=(JSONObject)JSONPointer.getObject(obj,pointer); 
    System.out.println(subobj); // Output the object 
    System.out.println(pointers.get(pointer)); // Output the key's value 
} 

uscita Esempio:

{"second-key":"second-value","first-key":"first-value"} 
Comment 

Dal JSON Pointer è nuovo, ho scritto la mia implementazione di esso e lo incluse nel Gist GitHub.


Ecco altri esempi per chiarire.

Data questa matrice JSON (utilizzare JSONArray anziché JSONObject in questo esempio):

[{ # foo 
"foo-key":"foo-value"}, 
{ # This is a 
# quite long comment. 
"bar-key":"bar-value"}] 

Il risultato sarebbe:

{"foo-key":"foo-value"} 
foo 
{"bar-key":"bar-value"} 
This is a quite long comment. 

Come risultato, più commenti sono fuse in un singolo commento . Ma dato questo array JSON:

[{ # foo 
"foo-key":"foo-value"}, 
{ # This is a 
# quite long comment. 
"bar-key":"bar-value" 
# This is another comment. 
    }] 

Il risultato sarebbe:

{"foo-key":"foo-value"} 
foo 
{"bar-key":"bar-value"} 
This is another comment. 

Di conseguenza, più commenti che si sono verificati in più punti sull'oggetto "bar" non sono coalizzati.

+0

Solo per verificare se sto capendo: questo consente solo un commento per oggetto? –

+0

L'implementazione corrente raggruppa i commenti che si verificano uno accanto all'altro, ma non i commenti che si verificano in posizioni diverse all'interno dello stesso oggetto secondario. Lo chiarirò con ulteriori esempi. –

+0

Puoi dirmi se questa soluzione funziona per te? –

0

altri sistemi consumano questo stesso JSON e le annotazioni devono essere trasparenti per loro, pertanto la struttura JSON non possono essere modificati aggiungendo proprietà per i commenti invece

Uso osservazioni messaggi passare i dati tra i sistemi non sembra una buona pratica. . Per esempio. XML non lo supporterebbe.

Perché non incorporare semplicemente i "commenti" importanti come dati? Questo è quello che succede se l'altro sistema lo sta usando. : ^)

+0

"Usare commenti nei messaggi per passare dati tra sistemi non sembra una buona pratica." Concordato. Per quanto riguarda "se l'altro sistema lo sta usando": ciò che intendo per "le annotazioni devono essere trasparenti per loro" è che i dati dei commenti non possono essere nel JSON è che non può essere aggiunto come una nuova chiave all'oggetto JSON - quindi l'altro sistema elaborerà le annotazioni a cui non si suppone. –

+0

Ah, capisco. Quindi i commenti non sono usati come dati. Tutto bene. :) –