Эликсир: поиск по значению префикса во вложенном JSON

Я пытаюсь найти URL-адреса во вложенном ответе JSON и отобразить их. Моя функция до сих пор выглядит так:

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?

1 ответ

Решение

Для этого вам придется использовать рекурсивную функцию, которая обрабатывает три типа данных:

  1. Для карты он повторяется по всем своим значениям.
  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"]
Другие вопросы по тегам