2015-12-29 25 views
10

Sto cercando di capire un problema con la manipolazione di JSON con obiettivi Aeson. Il mio compito è tanto semplice quanto aggiungere una chiave a un oggetto nidificato in JSON. Sono stato in grado di cambiare i mezzi keyby esistenti:Utilizzo dell'obiettivo per aggiungere chiave e valore a una mappa nidificata

> :set -XOverloadedStrings 
> import Control.Lens 
> import Data.Aeson 
> import Data.Aeson.Lens 
> "{ \"a\": { \"b\": 10 } }" & key "a" . key "b" .~ String "jee" 
"{\"a\":{\"b\":\"jee\"}}" 

Ma quando provo a farlo trattare con la nuova chiave, non riesce solo in silenzio per aggiungerlo:

> "{ \"a\": { \"b\": 10 } }" & key "a" . key "c" .~ String "jee" 
"{\"a\":{\"b\":10}}" 

Certamente sono io a fare Qualcosa non va, ma immagino di essere fuori di mana per capire cosa esattamente.

Vuoi gentilmente indicarmi la giusta direzione?

Grazie!

risposta

15

Come si nota, è possibile inserire at nelle mappe, mentre key e ix attraversano semplicemente gli elementi se esistono. Siamo in grado di effettuare le seguenti operazioni:

> "{ \"a\": { \"b\": 10 } }" & key "a" . _Object . at "c" ?~ String "foo" 
"{\"a\":{\"b\":10,\"c\":\"foo\"}} 

at è una lente di focalizzazione sul Maybe element -s, e possiamo inserire impostando ad Just qualche elemento, e rimuovere impostando a Nothing. at "c" ?~ String "foo" corrisponde a at "c" .~ Just (String "foo").

Se vogliamo fare inserti annidati, possiamo usare non per definire un valore predefinito da inserire:

> "{ \"a\": { \"b\": 10 } }" & key "a" . _Object . at "c" . non (Object mempty) . _Object . at "d" ?~ String "foo" 
"{\"a\":{\"b\":10,\"c\":{\"d\":\"foo\"}}}" 

Si tratta di un boccone, in modo che possiamo fattorizzare alcune parti out:

> let atKey k = _Object . at k 
> "{ \"a\": { \"b\": 10 } }" & key "a" . atKey "c" . non (Object mempty) . atKey "d" ?~ String "foo" 
+0

Grazie per aver fornito un esempio funzionante per il mio caso e ulteriori spiegazioni! – SkyWriter

3

key è basato su ix, la cui documentazione indica che non è abbastanza potente da fare ciò che si desidera e punta a Control.Lens.At.at. Sono abbastanza sicuro che dovrebbe fare il trucco per te. L'idea di base è iniziare con il prisma _Object per trasformare il testo JSON in un oggetto, quindi utilizzare at key per ottenere un obiettivo in quel campo come Maybe. È quindi possibile cambiarlo in Just quello che vuoi.

Questo funzionerà molto bene finché tutti gli oggetti lungo il percorso che si desidera prendere esistono. Se vuoi (potenzialmente) partire dal nulla e creare una catena di oggetti a campo singolo, probabilmente troverai le cose più fastidiose. Fortunatamente, probabilmente non hai bisogno di farlo.

+0

Grazie per aver sottolineato i motivi per cui 'key' non funziona per il mio caso. Ho davvero provato a guardare nel codice sorgente, ma ha ancora meno senso :-) Immagino che ci vuole del tempo per capirlo. – SkyWriter

+0

@SkyWriter, se si ha familiarità con la terminologia model/view, si può pensare a '_Object' come a fornire una vista 'Object' completa' di un modello' Text', ma solo se il 'Text' viene analizzato correttamente come 'Object'. Supponendo che la vista abbia esito positivo, è possibile sia ispezionare che modificare il modello 'Testo' attraverso quella vista. – dfeuer