Elixir - 嵌套 JSON 解析为结构
Elixir - Nested JSON parsing to structs
免责声明:我已经检查了问题 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)
?
无论如何,在尝试实施之前,我想知道是否有我没有看到的东西。
目前,我知道的唯一选择是为 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
太容易混淆了,应该重命名其中一个。如果我有时间,也许我会提出这些建议并与 Poison 建立一个 PR。
我相信上面的内容现在可以用 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{}})
免责声明:我已经检查了问题 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)
?
无论如何,在尝试实施之前,我想知道是否有我没有看到的东西。
目前,我知道的唯一选择是为 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
太容易混淆了,应该重命名其中一个。如果我有时间,也许我会提出这些建议并与 Poison 建立一个 PR。
我相信上面的内容现在可以用 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{}})