将json映射提取到struct的更好方法

时间:2018-08-07 15:33:05

标签: json parsing elixir

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

我知道我想要什么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。 然后,数据将保存到数据库中。

谢谢

1 个答案:

答案 0 :(得分:3)

我将存储id到字段名称的映射。这样,在reduce中就不需要任何if。某些模式匹配也将使其不必要执行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