Skip to content

Instantly share code, notes, and snippets.

@zookzook
Created August 13, 2019 14:33
Show Gist options
  • Select an option

  • Save zookzook/f692803df3d8c902f51cba2a1e2a051c to your computer and use it in GitHub Desktop.

Select an option

Save zookzook/f692803df3d8c902f51cba2a1e2a051c to your computer and use it in GitHub Desktop.
Parsing LDIF content file with NimbleParsec in Elixir
defmodule Ldif do
import NimbleParsec
name= ascii_string([?a..?z, ?A..?Z, ?0..?9], min: 1)
eol = ascii_char([?\n]) |> ignore()
assigment =
choice([
string("::") |> replace(:base64),
string(":") |> replace(:string)
])
rest_value = ignore(string(" ")) |> ascii_string([32..255], min: 1) |> concat(eol)
value = ascii_string([32..255], min: 1) |> concat(eol) |> repeat(rest_value)
attribute = name |> concat(assigment) |> ignore(string(" ")) |> concat(value) |> tag(:attribute)
attributes = repeat(lookahead_not(eol) |> concat(attribute)) |> concat(eol)
defparsec :parseLdif,
ignore(string("dn")) |> ignore(string(": ")) |> concat(value) |> tag(:dn)
|> concat(attributes)
def ldif(src) do
Enum.reverse(parse_ldif(src, []))
end
defp parse_ldif("", xs), do: xs
defp parse_ldif(src, xs) do
with {:ok, result, rest, %{}, _, _} <- parseLdif(src) do
record = Enum.reduce(result, %{}, fn
{:dn, [dn]}, m -> Map.put(m, "dn", dn)
{:attribute, attr}, m -> process_attribute(m, attr)
end)
parse_ldif(rest, [record | xs])
end
end
defp update_map(map, key, value) do
case Map.get(map, key, nil) do
nil -> Map.put(map, key, value)
xs when is_list(xs) -> Map.put(map, key, [value | xs])
other -> Map.put(map, key, [value, other] )
end
end
defp process_attribute(result, [key, :string, value]) do
update_map(result, key, value)
end
defp process_attribute(result, [key, :base64, value]) do
update_map(result, key, Base.decode64!(value) )
end
defp process_attribute(result, [key | [:base64 | xs]]) do
update_map(result, key, Base.decode64!(Enum.join(xs, "")))
end
end
@zookzook
Copy link
Author

Example:

ldif = """
dn: id=1,ou=Employees,o=company
id: 1
mail: [email protected]
gender: W
postalCode: 123
street:: xbtlbGlnb3dza2llZ28gOC8xMA==
givenname: Fred
sn: Anderson
c: PL
cn: Fred Anderson
l:: xYHDs2TFug==

"""

 Ldif.ldif(ldif)
[
  %{
    "c" => "PL",
    "cn" => "Fred Anderson",
    "dn" => "id=1,ou=Employees,o=company",
    "gender" => "W",
    "givenname" => "Fred",
    "id" => "1",
    "l" => "Łódź",
    "mail" => "[email protected]",
    "postalCode" => "123",
    "sn" => "Anderson",
    "street" => "Żeligowskiego 8/10" 
  }
]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment