Elixir - 嵌套JSON解析到结构

时间:2015-06-15 21:55:41

标签: json elixir

免责声明:我已经检查了here这个问题并且它没有回复我的问题。

我试图找到一种嵌套结构解析JSON的方法。例如:

{"name": "blah blah", "address": {"street": "smthing"}}

我想达到这个结果:

%User{name: "blah blah", address: %Address{street: "smthing"}}

因为这样可以更容易地插入验证(使用Vex进行验证)。

我知道Poison支持“as struct”选项,但它不提供嵌套。以上内容将被解析:

%User{name: "blah blah", address: %{"street" => "smthing"}}. 

我知道我可以为模块User编写一个解码器实现,但我想这不是预期的用例,它不是通用的。

当想知道一个实现时,我找不到一种方法来判断一个原子是否是一个模块...也许我必须使用:code.is_loaded(module_name)

无论如何,在尝试实施之前,我想知道是否有一些我没有看到的东西。

2 个答案:

答案 0 :(得分:9)

我相信Poison可以实现上述目标:

defmodule User do
  @derive [Poison.Encoder]
  defstruct [:address]
end

defmodule Address do
  @derive [Poison.Encoder]
  defstruct [:street]
end

Poison.decode(response, as: %User{address: %Address{}})

答案 1 :(得分:5)

目前,我所知道的唯一选择是为Poison.Decoder提供您自己的实现(请注意尾随r)协议。这样做的另一个好处是,您可以在一个位置进行这些转换,只需编写as: User即可正确转换地址。例如:

defimpl Poison.Decoder, for: User do
  def decode(task_list, options) do
    Map.update! task_list, :address, fn address ->
      Poison.Decode.decode(address, Keyword.merge(options, as: [Address]))
    end
  end
end

请注意,对decode的内部调用不是来自Poison.Decoder,而是 Poison.Decode ,而模块名称中没有r。如果你使用了错误的错误,你就不会收到错误,它只是不起作用,调试很麻烦。

从长远来看,我认为需要在Poison中完成一些工作才能使所有这些工作变得更有趣。也许是一个宏,可以更容易地为自定义结构编写Poison.Decoder实现。也许还支持像as: %User{address: Address}这样的嵌套结构选项,这些选项不应该太难实现。另外我认为模块名称DecodeDecoder太容易混淆,其中一个应该重命名。如果我有时间,也许我会提出这些建议,并设立一个带毒药的公关。