Elixir - 嵌套JSON解析到结构

Oli*_*asc 10 json elixir

免责声明:我在这里检查过这个问题并没有回答我的问题.

我试图想出一种嵌套结构解析JSON的方法.例:

{"name": "blah blah", "address": {"street": "smthing"}}
Run Code Online (Sandbox Code Playgroud)

我想达到这个结果:

%User{name: "blah blah", address: %Address{street: "smthing"}}
Run Code Online (Sandbox Code Playgroud)

因为这样可以更容易地插入验证(使用Vex作为exapmle).

我知道Poison支持"as struct"选项,但它不提供嵌套.以上将被解析:

%User{name: "blah blah", address: %{"street" => "smthing"}}. 
Run Code Online (Sandbox Code Playgroud)

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

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

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

Mai*_*kon 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{}})
Run Code Online (Sandbox Code Playgroud)


Pat*_*ity 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
Run Code Online (Sandbox Code Playgroud)

请注意,内部调用decode不是来自Poison.Decoder,而是 Poison.Decode没有r模块名称中的尾随.如果你使用了错误的错误,你将不会收到错误,它只是不起作用,这可能是一个痛苦的调试.

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