首页 > 解决方案 > 将json映射提取到结构中的更好方法

问题描述

我是 elixir 的新手,我想解析一个 json 文件。其中一个部分是对象的问答数组。[ { "questionId":1, "question":"信息:个人信息:名字", "answer":"Joe" }, { "questionId":3, "question":"信息:个人信息:姓氏", "答案":"史密斯" }, ... ]

我知道我想要什么 questionId,我将为 1 = 名字,2 = 姓氏制作地图。

但目前我正在执行以下操作以将数据放入结构中。

defmodule Student do

  defstruct first_name: nil, last_name: nil, student_number:  nil

  defguard is_first_name(id) when id == 1

  defguard is_last_name(id) when id == 3

  defguard is_student_number(id) when id == 7

end

defmodule AFMC do

  import Student
  @moduledoc """
  Documentation for AFMC.
  """

  @doc """
  Hello world.

  ## Examples

      iex> AFMC.hello
      :world

  """
  def main do
    get_json()
    |> get_outgoing_applications
  end

  def get_json do
    with {:ok, body} <- File.read("./lib/afmc_import.txt"),
          {:ok,body} <- Poison.Parser.parse(body), do: {:ok,body}
  end

  def get_outgoing_applications(map) do
    {:ok,body} = map
    out_application = get_in(body,["outgoingApplications"])


    Enum.at(out_application,0)
    |> get_in(["answers"])
    |> get_person
  end

  def get_person(answers) do

    student = Enum.reduce(answers,%Student{},fn(answer,acc) ->

      if Student.is_first_name(answer["questionId"]) do

        acc = %{acc | first_name: answer["answer"]}

      end

      if Student.is_last_name(answer["questionId"]) do

        acc = %{acc | last_name: answer["answer"]}

      end

      if Student.is_student_number(answer["questionId"]) do

        acc = %{acc | student_number: answer["answer"]}

      end

      acc

    end)

    IO.inspect "test"
    s



  end


end

我想知道什么是更好的方法来做 get_person 而不必做 if 语句。如果我知道我将在对象数组中将 1 映射到 questionId 1。然后将数据保存到数据库中。

谢谢

标签: jsonparsingelixir

解决方案


我会存储 id 到字段名称的映射。这样你就不需要if在reduce里面有任何东西了。一些模式匹配也会使得它没有必要做answer["questionId"]等等。

defmodule Student do
  defstruct first_name: nil, last_name: nil, student_number: nil

  @fields %{
    1 => :first_name,
    3 => :last_name,
    7 => :student_number
  }

  def parse(answers) do
    Enum.reduce(answers, %Student{}, fn %{"questionId" => id, "answer" => answer}, acc ->
      %{acc | @fields[id] => answer}
    end)
  end
end

IO.inspect(
  Student.parse([
    %{"questionId" => 1, "question" => "", "answer" => "Joe"},
    %{"questionId" => 3, "question" => "", "answer" => "Smith"},
    %{"questionId" => 7, "question" => "", "answer" => "123"}
  ])
)

输出:

%Student{first_name: "Joe", last_name: "Smith", student_number: "123"}

编辑:要跳过地图中不存在的 ID,请更改:

%{acc | @fields[id] => answer}

到:

if field = @fields[id], do: %{acc | field => answer}, else: acc

推荐阅读