0

我正在尝试在嵌套的 JSON 响应中查找 URL 并将它们映射。到目前为止,我的功能如下所示:

def list(env, id) do
  Service.get_document(env, id)
  |> Poison.decode!
  |> Enum.find(fn {_key, val} -> String.starts_with?(val, 'https') end)
end

JSON 大致如下所示:

  "stacks": [
    {
      "boxes": [
        {
          "content": "https://ddd.cloudfront.net/photos/uploaded_images/000/001/610/original/1449447147677.jpg?1505956120",
          "box": "photo"
        }
      ]
    }
  ],
  "logo": "https://ddd.cloudfront.net/users/cmyk_banners/000/000/002/original/banner_CMYK.jpg?1397201875"

因此 URL 可以有任何键,并且可以处于任何级别。

使用该代码,我收到此错误:

no function clause matching in String.starts_with?/2

有人有更好的方法在 JSON 响应中找到吗?

4

1 回答 1

3

为此,您必须使用递归函数,它处理三种类型的数据:

  1. 对于 map,它会递归其所有值。
  2. 对于列表,它递归其所有元素。
  3. 对于字符串,它选择以“https”开头的字符串

这是一个简单的实现,它接受一个术语和一个字符串来检查starts_with?

defmodule A do
  def recursive_starts_with(thing, start, acc \\ [])

  def recursive_starts_with(binary, start, acc) when is_binary(binary) do
    if String.starts_with?(binary, start) do
      [binary | acc]
    else
      acc
    end
  end
  def recursive_starts_with(map, start, acc) when is_map(map) do
    Enum.reduce(map, acc, fn {_, v}, acc -> A.recursive_starts_with(v, start, acc) end)
  end
  def recursive_starts_with(list, start, acc) when is_list(list) do
    Enum.reduce(list, acc, fn v, acc -> A.recursive_starts_with(v, start, acc) end)
  end
end

data = %{
  "stacks" => [
    %{
      "boxes" => [
        %{
          "content" => "https://ddd.cloudfront.net/photos/uploaded_images/000/001/610/original/1449447147677.jpg?1505956120",
          "box" => "photo"
        }
      ]
    }
  ],
  "logo" => "https://ddd.cloudfront.net/users/cmyk_banners/000/000/002/original/banner_CMYK.jpg?1397201875"
}

data |> A.recursive_starts_with("https") |> IO.inspect

输出:

["https://ddd.cloudfront.net/photos/uploaded_images/000/001/610/original/1449447147677.jpg?1505956120",
 "https://ddd.cloudfront.net/users/cmyk_banners/000/000/002/original/banner_CMYK.jpg?1397201875"]
于 2017-10-09T04:37:12.973 回答