2015-12-29 4 views
10

Je n'arrive pas à résoudre un problème de manipulation de JSON avec des objectifs Aeson. Ma tâche est aussi simple que d'ajouter une clé à un objet imbriqué dans JSON. Je suis en mesure de changer les moyens de keyby existants de:Utilisation de l'objectif pour ajouter une touche et une valeur à une carte imbriquée

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

Mais lorsque je tente de faire face à la nouvelle clé, juste échoue silencieusement pour l'ajouter:

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

Certes, il est me faire Quelque chose ne va pas, mais je me dis que je suis hors de mana pour comprendre exactement quoi.

Pourriez-vous me diriger dans la bonne direction?

Merci!

Répondre

15

Comme le note dfeuer, at peut insérer dans les cartes, tandis que key et ix traversent simplement les éléments s'ils existent. Nous pouvons effectuer les opérations suivantes:

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

at est une lentille de focalisation sur Maybe element -s, et nous pouvons insérer en mettant à Just un élément, et de supprimer en mettant à Nothing. at "c" ?~ String "foo" est la même que at "c" .~ Just (String "foo").

Si nous voulons faire des inserts imbriqués, nous pouvons utiliser non pour définir une valeur par défaut à insérer:

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

C'est une bouchée, afin que nous puissions tenir compte des parties sur:

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

Merci de fournir un exemple de travail pour mon cas et des explications supplémentaires! – SkyWriter

3

key est basé sur ix, dont la documentation indique qu'il n'est pas assez puissant pour faire ce que vous voulez et indique Control.Lens.At.at. Je suis sûr que ça devrait faire l'affaire pour toi. L'idée de base est que vous commencez avec le prisme _Object pour transformer le texte JSON en objet, puis utilisez at key pour obtenir un objectif dans ce champ en tant que Maybe. Vous pouvez ensuite le changer en Just ce que vous voulez.

Cela fonctionnera très bien tant que tous les objets le long du chemin que vous souhaitez prendre existent. Si vous voulez (potentiellement) partir de rien et créer une chaîne d'objets à un seul champ, vous trouverez probablement des choses plus ennuyantes. Heureusement, vous n'avez probablement pas besoin de faire cela.

+0

Merci d'avoir signalé les raisons pour lesquelles 'key' ne fonctionne pas dans mon cas. J'ai vraiment essayé de regarder dans le code source, mais cela a encore moins de sens :-) Devinez qu'il faut du temps pour se faire une idée. – SkyWriter

+0

@SkyWriter, si vous êtes familier avec la terminologie modèle/vue, vous pouvez considérer '_Object' comme fournissant une vue complète' Object' d'un modèle 'Text', mais seulement si ce' Text' est analysé avec succès 'Object'. En supposant que la vue réussisse, vous pouvez à la fois inspecter et modifier le modèle 'Text' à travers cette vue. – dfeuer