【问题标题】:Map JSON values in Elixir在 Elixir 中映射 JSON 值
【发布时间】:2018-04-30 22:57:18
【问题描述】:

我已经使用 Posion.decode 解析了以下 JSON!

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}}}

我想对此进行映射,但由于节点元素中的文本发生变化,我无法获取 JSON 元素。 目前我已经尝试过了。

Enum.map(json , fn(item) ->
%{
  color: item.attributes["color"],                 
  size: item.attributes["size"],
  price: item.pricing["standard"] * 100,
  isAvailable: item.isAvailable
 }
end)

但是这段代码给出了一些与访问相关的错误。

【问题讨论】:

    标签: elixir jsonparser elixir-poison


    【解决方案1】:

    在映射映射时,迭代的键值对作为元组 {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"}
    # ]
    

    这里我们对 mapper 中的值使用就地模式匹配来简化匹配器本身的代码,并使其在输入错误的情况下不易出错。

    【讨论】:

      【解决方案2】:

      三件事:

      1. 你有一张地图,所以Enum.map 会给你一个键和值的元组。你只想要这里的值,所以这样做:

        fn {_, item} ->
        
      2. 地图中的键是字符串。点语法仅适用于原子键。你需要做的:

        item["attributes"]
        

        而不是

        item.attributes
        

        其他键也类似。

      3. 你的价格是一个字符串。您需要先将其转换为浮点数,然后才能将其相乘。您可以使用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"}]
      

      【讨论】:

        【解决方案3】:

        您会遇到访问错误,因为如果 property 是一个原子并且在您的 json 映射中,键是字符串,您只能使用 thing.property 语法。

        让这更容易的一件事是Poison.decode 可以接受keys: :atoms 的第二个参数来返回一个带有原子键的映射。使用您在这里拥有的东西,这将解决问题:

        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)
        

        【讨论】:

        • 警告词:原子不会被垃圾收集,所以如果你用不同的键解析大量 JSON,这可能会成为一个问题。 github.com/devinus/poison#parser
        • 有一个原子限制,它们还没有被垃圾收集(还),但在这种情况下,JSON 具有一致的形状。所以创建的唯一原子是:size、:color、:price 和:is_available。我从未见过任何应用接近 FWIW 的限制。
        猜你喜欢
        • 1970-01-01
        • 2023-04-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-15
        • 1970-01-01
        • 1970-01-01
        • 2020-12-18
        相关资源
        最近更新 更多