免责声明:我已经检查了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)
?
无论如何,在尝试实施之前,我想知道是否有一些我没有看到的东西。
答案 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}
这样的嵌套结构选项,这些选项不应该太难实现。另外我认为模块名称Decode
和Decoder
太容易混淆,其中一个应该重命名。如果我有时间,也许我会提出这些建议,并设立一个带毒药的公关。