2016-08-17 9 views
1

私はそれが厳密にSUPのparamのためですがfetch(1) |> decode_responseが動作しません行うエリキシル:文字列内のリスト項目の数をカウントする方法

iex(1)> fetch(1) 
{:ok, 
"{\"name\":\"Anabela\",\"surname\":\"Neagu\",\"gender\":\"female\",\"region\":\"Romania\"}"} 
iex(2)> fetch(2) 
{:ok, 
"[{\"name\":\"Juana\",\"surname\":\"Su├írez\",\"gender\":\"female\",\"region\":\"Argentina\"},{\"name\":\"ðíðÁÐÇð│ðÁð╣\",\"surname\":\"ðƒð╗ð¥Ðéð¢ð©ð║ð¥ð▓\",\"gender\":\"male\",\"region\":\"Russia\"}]"} 

毒を使用して、次のJSON文字列をデコードしようとしています1.

私は次のエラー

10:07:52.663 [error] GenServer Newsequence.Server terminating 
** (BadMapError) expected a map, got: {"gender", "female"} 
    (stdlib) :maps.find("gender", {"gender", "female"}) 
    (elixir) lib/map.ex:145: Map.get/3 
    lib/poison/decoder.ex:49: anonymous fn/3 in Poison.Decode.transform_struct/4 
    (stdlib) lists.erl:1262: :lists.foldl/3 
    lib/poison/decoder.ex:48: Poison.Decode.transform_struct/4 
    lib/poison/decoder.ex:24: anonymous fn/5 in Poison.Decode.transform/4 
    (stdlib) lists.erl:1262: :lists.foldl/3 
    lib/poison/decoder.ex:24: Poison.Decode.transform/4 Last message: {:getpeople, 1} State: {[], #PID<0.144.0>} 
を持っています

My機能は以下の通りです:

def decode_response({:ok, body}) do 
    Poison.decode!(body, as: [%Personne{}]) 
end 

私は、関数が

def decode_response({:ok, body}) do 
     Poison.decode!(body, as: %Personne{}) 
    end 

する必要があり、1に等しいのparamのためだと思う私は最終的に私のフェッチ機能により、指定された文字列内のタプルをカウントしているdecode_responseを選択するためにガードを使用することは良いアイデアだと思いました使用するが、私はどのようにわからない。

誰かが正しい方向に向いていますか?

よろしく、

ピエール

答えて

1

あなたは、Poison.decode!/1を使用してネイティブマップ/リストに第1の復号することによってこれを行う、その後as:ために、関連する値を計算して、最終的にはネイティブのデータ構造を持つPoison.Decoder.decode/2と呼び出すことができます

def decode_response({:ok, body}) do 
    parsed = Poison.decode!(body) 
    as = 
    cond do 
     is_map(parsed) -> %Personne{} 
     is_list(parsed) -> [%Personne{}] 
    end 
    Poison.Decoder.decode(parsed, as: as) 
end 

デモ:にデコードする構造

defmodule Personne do 
    defstruct [:name, :surname, :gender, :region] 
end 

defmodule Main do 
    def main do 
    f1 = {:ok, "{\"name\":\"Anabela\",\"surname\":\"Neagu\",\"gender\":\"female\",\"region\":\"Romania\"}"} 
    f2 = {:ok, "[{\"name\":\"Juana\",\"surname\":\"Su├írez\",\"gender\":\"female\",\"region\":\"Argentina\"},{\"name\":\"ðíðÁÐÇð│ðÁð╣\",\"surname\":\"ðƒð╗ð¥Ðéð¢ð©ð║ð¥ð▓\",\"gender\":\"male\",\"region\":\"Russia\"}]"} 

    f1 |> decode_response |> IO.inspect 
    f2 |> decode_response |> IO.inspect 
    end 

    def decode_response({:ok, body}) do 
    parsed = Poison.decode!(body) 
    as = 
     cond do 
     is_map(parsed) -> %Personne{} 
     is_list(parsed) -> [%Personne{}] 
     end 
    Poison.Decoder.decode(parsed, as: as) 
    end 
end 

Main.main 

出力:

%{"gender" => "female", "name" => "Anabela", "region" => "Romania", 
    "surname" => "Neagu"} 
[%{"gender" => "female", "name" => "Juana", "region" => "Argentina", 
    "surname" => "Suárez"}, 
%{"gender" => "male", "name" => "ðíðÁÐÇð│ðÁð╣", 
    "region" => "Russia", 
    "surname" => "ðƒð╗ð¥Ðéð¢ð©ð║ð¥ð▓"}] 
0

それは少しナイーブだが、それはJSONの第二の解析やって保存しましょう:あなたはエリクサー1.2上か、あなたを下回る場合、

if (body |> String.trim_leading() |> String.starts_with?("[")) do 
    Poison.decode!(body, as: [%Personne{}])      
else              
    Poison.decode!(body, as: %Personne{})      
end 

注意をString.trim_leading/1の代わりにString.lstrip/1を使用します。

これを行うには別の方法としてマップとしてデコードし、String.to_existing_atom/1を使用してキーを変換してからKernel.struct/2を使用して構造体に変換します。

def decode_response({:ok, body}) do 
    body |> Poison.decode!() |> string_map_struct(Personne) 
    end 

    defp string_map_struct(entry, module) do 
    params = 
     entry 
     |> Enum.map(fn {key, val} -> 
     key = to_existing_atom(key) 
     {key, val} 
     end) 
     |> Enum.into(%{}) 
    struct(module, params) 
    end 

    defp to_existing_atom(key) do 
    try do 
     String.to_existing_atom(key) 
    rescue 
     ArgumentError -> key 
    end 
    end 
+0

(以下のDogbertの解決策のように)もう少し簡単なものを探していましたが、あなたのことを注意深く見ていきます。本当に面白そうです。 – Tanc

関連する問題