Reputation: 1400
I have 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'm unable to get JSON elements as the text in the node element changes. So far I've 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 error related to accessing.
Upvotes: 4
Views: 5152
Reputation: 2925
You're getting access errors because you can only use the thing.property
syntax if property
is an atom and in your json map, the keys are strings.
One thing that will make this much easier is that Poison.decode
can take a second argument of keys: :atoms
to return a map with atom 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)
Upvotes: 1
Reputation: 121010
While mapping the map, the iterated key-value pairs come to the 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 an inplace pattern matching for values in mapper to simplify the code of matcher itself and make it less error-prone in a case of bad input.
Upvotes: 5
Reputation: 222428
Three things:
You have a map so Enum.map
will give you a tuple of key and value. You just want the value here, so do:
fn {_, item} ->
The keys in your map are strings. The dot syntax only works for atom keys. You need to do:
item["attributes"]
instead of
item.attributes
and similar for other keys.
The price you have is a string. You'll need to convert it to a Float before you can multiply it. You can do it like this using String.trim_leading
and String.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
Output:
[%{color: "Black", isAvailable: true, price: 4.15e4, size: "11"},
%{color: "Black", isAvailable: true, price: 4.15e4, size: "11"}]
Upvotes: 2