Use Poison to decode map of structs

Hey everyone,
I was wondering if there is a chance to decode am map from json to a map of predefined structs. Important is that the keys are not predefined.

So in the end I would love to transform this

{
  "text": "A pet food distribution center where the animal can tap the screen and receive a treat or meal. Would allow for healthy regulation and training.",
  "annotation_candidates": {
    "tap": {
      "text": "tap",
      "resource_candidates": [
        {
          "label": "Tap water",
          "resource": "http://dbpedia.org/resource/Tap_water"
        },
        {
          "label": "Tap dance",
          "resource": "http://dbpedia.org/resource/Tap_dance"
        }
      ]
    },
    "receive": {
      "name": "receive",
      "offset": 71,
      "resource_candidates": [
        {
          "label": "Radio receiver",
          "resource": "http://dbpedia.org/resource/Radio_receiver"
        }
      ]
    }
  ]
}

into this

%AnnotationCandidates{
  text: "A pet food distribution center where the animal can tap the screen and receive a treat or meal. Would allow for healthy regulation and training.",
  annotation_candidates: %{
    "tap" => %AnnotationCandidate{
      text: "tap",
      offset: 52,
      resource_candidates: [
        %ResourceCandidate{
          label: "Tap Water"
          resource: "http://dbpedia.org/resource/Tap_water",
                confidence: 0.2600142258675502
        }, 
        %ResourceCandidate{ ... }
      ]
    },
    "receive" => %AnnotationCandidate{ ... }
  }
}

I don’t know if that is possible (or a dumb idea)

Thank you for your help.

It looks it’s not really valid json because of extra commas… without, You might

iex(29)> json = ~s(
...(29)>   {
...(29)>     "text": "A pet food distribution center where the animal can tap the screen and receive a treat or meal. Would allow for healthy regulation and training.",
...(29)>     "annotation_candidates": {
...(29)>       "tap": {
...(29)>         "text": "tap",
...(29)>         "resource_candidates": [
...(29)>           {
...(29)>             "label": "Tap water",
...(29)>             "resource": "http://dbpedia.org/resource/Tap_water"
...(29)>           },
...(29)>           {
...(29)>             "label": "Tap dance",
...(29)>             "resource": "http://dbpedia.org/resource/Tap_dance"
...(29)>           }
...(29)>         ]
...(29)>       }
...(29)>     }
...(29)>   }
...(29)> )
"\n  {\n    \"text\": \"A pet food distribution center where the animal can tap the screen and receive a treat or meal. Would allow for healthy regulation and training.\",\n    \"annotation_candidates\": {\n      \"tap\": {\n        \"text\": \"tap\",\n        \"resource_candidates\": [\n          {\n            \"label\": \"Tap water\",\n            \"resource\": \"http://dbpedia.org/resource/Tap_water\"\n          },\n          {\n            \"label\": \"Tap dance\",\n            \"resource\": \"http://dbpedia.org/resource/Tap_dance\"\n          }\n        ]\n      }\n    }\n  }\n"
iex(30)> Jason.decode json
{:ok,
 %{
   "annotation_candidates" => %{
     "tap" => %{
       "resource_candidates" => [
         %{
           "label" => "Tap water",
           "resource" => "http://dbpedia.org/resource/Tap_water"
         },
         %{
           "label" => "Tap dance",
           "resource" => "http://dbpedia.org/resource/Tap_dance"
         }
       ],
       "text" => "tap"
     }
   },
   "text" => "A pet food distribution center where the animal can tap the screen and receive a treat or meal. Would allow for healthy regulation and training."
 }}

If it’s not json compliant, it returns an error. For example if You add commas at the end of resource lines.

You can see this document.

PS: I use Jason instead of Poison, but it might be the same problem.
Once You have struct, it’s easy to finish your transformation.

You can’t go from a JSON into a struct directly, but you can go from a JSON to a Map and then use the map to create a Struct.

I recommend you are a look at Jason. Once you have a map or a keyword list, have a look that struct(map, opts) and you will be ready to go.

1 Like

I’m using Posion so far with @derive [Poison.Encoder] and it works really well if I know the keys of the map beforehand.

Structs have fixed keys. So if you don’t know the keys ahead of time then you can’t use a structural and need to use a map instead.

1 Like