defmodule JsonToXml do import XmlBuilder @moduledoc """ Documentation for JsonToXml. """ @doc """ Converts the given json string into a xml string. Raise exceptions if someting goes wrong. The document root is added with the tag ``. Elements in arrays are wrapped in `` tags like so: ``` json { "list": ["apple", "banana"] } ``` is converted to ``` xml apple banana ``` ## Examples iex>JsonToXml.convert!(~s({ "firstname": "John", "lastname": "Doe" })) "\\n\\n\\tJohn\\n\\tDoe\\n" iex>JsonToXml.convert!(~s({ "name": { "first": "John", "last": "Doe" } })) "\\n\\n\\t\\n\\t\\tJohn\\n\\t\\tDoe\\n\\t\\n" iex>JsonToXml.convert!(~s({ "person": { "name": "Doe", "address": { "street": "Huffman Road", "number": 12}} })) "\\n\\n\\t\\n\\t\\t
\\n\\t\\t\\t12\\n\\t\\t\\tHuffman Road\\n\\t\\t
\\n\\t\\tDoe\\n\\t
\\n
" iex>JsonToXml.convert!(~s({ "list": ["apple", "banana", "lemon"] })) "\\n\\n\\t\\n\\t\\tapple\\n\\t\\tbanana\\n\\t\\tlemon\\n\\t\\n" """ def convert!(json) do content = Poison.decode!(json) |> map_elements() XmlBuilder.doc("root", content) end @doc """ Converts the given json string into a xml string. The document root is added with the tag ``. Elements in arrays are wrapped in `` tags like so: ``` json { "list": ["apple", "banana"] } ``` is converted to ``` xml apple banana ``` ## Examples iex>JsonToXml.convert(~s({ "firstname": "John", "lastname": "Doe" })) {:ok, "\\n\\n\\tJohn\\n\\tDoe\\n"} iex>JsonToXml.convert(~s({ "name": { "first": "John", "last": "Doe" } })) {:ok, "\\n\\n\\t\\n\\t\\tJohn\\n\\t\\tDoe\\n\\t\\n"} iex>JsonToXml.convert(~s({ "person": { "name": "Doe", "address": { "street": "Huffman Road", "number": 12}} })) {:ok, "\\n\\n\\t\\n\\t\\t
\\n\\t\\t\\t12\\n\\t\\t\\tHuffman Road\\n\\t\\t
\\n\\t\\tDoe\\n\\t
\\n
"} iex>JsonToXml.convert(~s({ "list": ["apple", "banana", "lemon"] })) {:ok, "\\n\\n\\t\\n\\t\\tapple\\n\\t\\tbanana\\n\\t\\tlemon\\n\\t\\n"} iex>JsonToXml.convert(~s( { "bogus": 1 )) {:error, {:invalid, 14}} """ def convert(json) do json |> Poison.decode() |> do_convert() end defp do_convert({:ok, decoded}) do content = map_elements(decoded) {:ok, XmlBuilder.doc("root", content)} end defp do_convert({:error, reason, line}) do {:error, {reason, line}} end @doc """ Converts the given json file into a xml string. ## Examples iex>JsonToXml.convert_file!("test/fixtures/example.json") "\\n\\n\\t
\\n\\t\\t12\\n\\t\\tHuffman Road\\n\\t
\\n\\t\\n\\t\\tfirst\\n\\t\\t\\n\\t\\t\\tsweet\\n\\t\\t\\tindigestive\\n\\t\\t\\n\\t\\tlemon\\n\\t\\n\\tJohn Doe\\n
" """ def convert_file!(file) do File.read!(file) |> convert!() end defp map_elements(elements) do Enum.map(elements, &create_element/1) end defp create_element({key, value}) when is_map(value) do element(key, map_elements(value)) end defp create_element({key, value}) when is_list(value) do array = Enum.reduce(value, [], &create_array_item/2) |> Enum.reverse() element(key, array) end defp create_element({key, value}) do element(key, value) end defp create_array_item(element, acc) do [create_element({"element", element}) | acc] end end