JSON Map in Elixir
I parsed the following JSON using Posion.decode!
json = %{"color-Black|size:10" =>
%{"attributes" => %{"color" => "Black","size" => "11"},
"isAvailable" => true,
"pricing" => %{"standard" => "$415.00", "sale" => 415}},
"color|size-EU:9.5" =>
%{"attributes" => %{"color" => "Black","size" => "11"},
"isAvailable" => true,
"pricing" => %{"standard" => "$415.00", "sale" => 415}}}
I want to map this, and I cannot get the JSON elements as text in the node element. So far I have tried.
Enum.map(json , fn(item) ->
%{
color: item.attributes["color"],
size: item.attributes["size"],
price: item.pricing["standard"] * 100,
isAvailable: item.isAvailable
}
end)
But this code gives some access related error.
When matching a map, repeating key-value pairs arrive in mapper as tuples {key, value}:
Enum.map(json, fn {_, %{"attributes" => attributes,
"isAvailable" => isAvailable,
"pricing" => pricing}} ->
%{
color: attributes["color"],
size: attributes["size"],
price: pricing["standard"],
isAvailable: isAvailable
}
end)
#โ [
# %{color: "Black", isAvailable: true, price: "$415.00", size: "11"},
# %{color: "Black", isAvailable: true, price: "$415.00", size: "11"}
# ]
Here we use inplace pattern matching for values โโin mapper to simplify the pairing code itself and make it less error prone in case of bad input.
Three things:
You have a map, so it
Enum.mapwill give you a set of keys and values. You just need the value here, so:fn {_, item} ->. . :
item["attributes"]item.attributes.
. Float, . ,
String.trim_leadingString.to_float:iex(1)> "$123.45" |> String.trim_leading("$") |> String.to_float 123.45
Enum.map(json, fn {_, item} ->
%{
color: item["attributes"]["color"],
size: item["attributes"]["size"],
price: item["pricing"]["standard"] |> String.trim_leading("$") |> String.to_float |> Kernel.*(100),
isAvailable: item["isAvailable"]
}
end)
|> IO.inspect
:
[%{color: "Black", isAvailable: true, price: 4.15e4, size: "11"},
%{color: "Black", isAvailable: true, price: 4.15e4, size: "11"}]
You get access errors because you can use the syntax thing.propertyif it propertyis an atom and there are lines on your json card.
One thing that will make this a lot easier is that it Poison.decodecan take a second argument keys: :atomsto return a map with atomic keys. Working with what you have here, this will solve the problem:
json_atoms = Poison.encode!(json) |> Poison.decode!(keys: :atoms)
convert_price = fn x ->
String.trim_leading(x, "$")
|> String.to_float
|> &(&1 * 100)
|> trunc
end
Enum.map(json_atoms, fn {_k,v} -> %{
color: v.attributes.color,
size: v.attributes.size,
price: convert_price.(v.pricing.standard),
isAvailable: v.isAvailable
} end)