Elixir:在嵌套 JSON 中按值前缀查找
Elixir: find by value prefix in nested JSON
我正在尝试在嵌套的 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 回复中查找吗?
你必须为此使用递归函数,它处理三种类型的数据:
- 对于 map,它对其所有值进行递归。
- 对于列表,它递归它的所有元素。
- 对于字符串,它选择以 "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"]
我正在尝试在嵌套的 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 回复中查找吗?
你必须为此使用递归函数,它处理三种类型的数据:
- 对于 map,它对其所有值进行递归。
- 对于列表,它递归它的所有元素。
- 对于字符串,它选择以 "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"]