Skip to content

Commit

Permalink
update documents and fix specs
Browse files Browse the repository at this point in the history
  • Loading branch information
bennyhat committed Oct 10, 2020
1 parent 10376cc commit f64b5fa
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 50 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,19 @@ iex> XmlJson.BadgerFish.serialize(%{"root" => %{"@attr" => "hello", "dog" => %{"
{:ok, "<root attr=\"hello\"><dog>cat</dog></root>"}
```

### AWS API
Based on common conventions seen in at least the EC2 and ELBv2 XML APIs
```elixir
iex> XmlJson.AwsApi.deserialize("<root><member><dog>cat</dog></member></root>")
{:ok, %{"root" => [%{"dog" => "cat"}]}}

iex> XmlJson.AwsApi.serialize(%{"root" => [%{"dog" => "cat"}]})
{:ok, "<root><member><dog>cat</dog><member></root>"}

iex> XmlJson.AwsApi.serialize_as_params(%{"root" => [%{"dog" => "cat"}, %{"dog" => "horse"}]})
{:ok, %{"root.member.1.dog" => "cat", "root.member.2.dog" => "horse"}}
```

## Installation

The package can be installed by adding `xml_json` to your list of dependencies
Expand Down
100 changes: 63 additions & 37 deletions lib/xml_json/aws_api.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,51 +9,77 @@ defmodule XmlJson.AwsApi do
alias XmlJson.AwsApi.Serializer
alias XmlJson.AwsApi.ParamsSerializer

# @type badgerfish_options ::
# %{
# exclude_namespaces: boolean()
# }
# | [
# exclude_namespaces: boolean()
# ]
@type aws_api_options ::
%{
list_element_names: list(binary())
}
| [
list_element_names: list(binary())
]

@default_opts %{
list_element_names: ["member"]
}

# @doc """
# Serializes the given Map.
@doc """
Serializes the given Map.
# Returns an `:ok` tuple with a Map serialized to XML
Returns an `:ok` tuple with a Map serialized to XML
# ## Examples
## Examples
# iex> XmlJson.BadgerFish.serialize(%{"alice" => %{"$" => "bob"}})
# {:ok, "<alice>bob</alice>"}
iex> XmlJson.AwsApi.serialize(%{"alice" => "bob"})
{:ok, "<alice>bob</alice>"}
# iex> XmlJson.BadgerFish.serialize(%{"alice" => %{"$" => "bob", "@xmlns" => %{"$" => "https://default.example.com"}}}, exclude_namespaces: true)
# {:ok, "<alice>bob</alice>"}
iex> XmlJson.AwsApi.serialize(%{"alice" => ["bob", "jane"]})
{:ok, "<alice><member>bob</member><member>jane</member></alice>"}
# """
"""
@spec serialize(map(), aws_api_options()) :: {:ok, binary()} | {:error, term()}
def serialize(object, opts \\ [])

def serialize(object, opts),
do: Serializer.serialize(object, merge_default_options(opts))

@spec serialize!(map(), aws_api_options()) :: binary()
def serialize!(map, opts \\ [])

def serialize!(map, opts) do
case serialize(map, opts) do
{:ok, xml} -> xml
{:error, reason} -> raise reason
end
end

@doc """
Serializes the given Map as a set request parameters.
Returns an `:ok` tuple with a Map serialized to a flattened Map
## Examples
iex> XmlJson.AwsApi.serialize_as_params(%{"alice" => "bob"})
{:ok, %{"alice" => "bob"}}
iex> XmlJson.AwsApi.serialize_as_params(%{"alice" => ["bob", "jane"]})
{:ok, %{"alice.member.1" => "bob", "alice.member.2" => "jane"}}
"""
@spec serialize_as_params(map(), aws_api_options()) :: {:ok, map()} | {:error, term()}
def serialize_as_params(object, opts \\ [])

def serialize_as_params(object, opts),
do: ParamsSerializer.serialize(object, merge_default_options(opts))

# @spec serialize!(map(), badgerfish_options()) :: binary()
# def serialize!(map, opts \\ [])
@spec serialize_as_params!(map(), aws_api_options()) :: map()
def serialize_as_params!(map, opts \\ [])

# def serialize!(map, opts) do
# case serialize(map, opts) do
# {:ok, xml} -> xml
# {:error, reason} -> raise reason
# end
# end
def serialize_as_params!(map, opts) do
case serialize_as_params(map, opts) do
{:ok, xml} -> xml
{:error, reason} -> raise reason
end
end

@doc """
Deserializes the given XML string.
Expand All @@ -62,29 +88,29 @@ defmodule XmlJson.AwsApi do
## Examples
iex> XmlJson.BadgerFish.deserialize("<alice>bob</alice>")
{:ok, %{"alice" => %{"$" => "bob"}}}
iex> XmlJson.AwsApi.deserialize("<alice>bob</alice>")
{:ok, %{"alice" => "bob"}}
iex> XmlJson.BadgerFish.deserialize("<alice xmlns=\\"https://default.example.com\\">bob</alice>", exclude_namespaces: true)
{:ok, %{"alice" => %{"$" => "bob"}}}
iex> XmlJson.AwsApi.deserialize("<alice><member>bob</member></alice>")
{:ok, %{"alice" => ["bob"]}}
"""
@spec deserialize(binary(), map()) :: {:ok, map()}
@spec deserialize(binary(), aws_api_options()) :: {:ok, map()} | {:error, term()}
def deserialize(xml, opts \\ [])

def deserialize(xml, opts) do
Deserializer.deserialize(xml, merge_default_options(opts))
end

# @spec deserialize!(binary(), badgerfish_options()) :: map()
# def deserialize!(xml, opts \\ [])
@spec deserialize!(binary(), aws_api_options()) :: map()
def deserialize!(xml, opts \\ [])

# def deserialize!(xml, opts) do
# case deserialize(xml, opts) do
# {:ok, element} -> element
# {:error, reason} -> raise reason
# end
# end
def deserialize!(xml, opts) do
case deserialize(xml, opts) do
{:ok, element} -> element
{:error, reason} -> raise reason
end
end

defp merge_default_options(provided) when is_map(provided) do
Map.merge(@default_opts, provided)
Expand Down
7 changes: 2 additions & 5 deletions lib/xml_json/aws_api/deserializer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule XmlJson.AwsApi.Deserializer do

alias XmlJson.SaxHandler

@spec deserialize(binary(), map()) :: {:ok, map()}
@spec deserialize(binary(), map()) :: {:ok, map()} | {:error, Saxy.ParseError.t()}
def deserialize(xml, opts) do
case SaxHandler.parse_string(xml) do
{:ok, element} ->
Expand All @@ -25,7 +25,6 @@ defmodule XmlJson.AwsApi.Deserializer do
defp update_children(aws, %{children: children}, opts) do
accumulate_children(aws, children, opts)
end

defp update_children(_aws, _no_children, _opts), do: nil

defp update_text(aws, %{text: ""}), do: aws
Expand Down Expand Up @@ -53,9 +52,7 @@ defmodule XmlJson.AwsApi.Deserializer do
else
map
end

map ->
map
map -> map
end
end

Expand Down
4 changes: 4 additions & 0 deletions lib/xml_json/aws_api/params_serializer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ defmodule XmlJson.AwsApi.ParamsSerializer do
An AWS implementation of serialization from a Map into Request Params
"""

@spec serialize(map(), map()) :: {:ok, map()} | {:error, term()}
def serialize(object, opts) do
params =
to_params("", object, opts)
|> List.flatten()
|> Map.new()

{:ok, params}

rescue
e -> {:error, e}
end

defp to_params(prefix, map, opts) when is_map(map) do
Expand Down
2 changes: 1 addition & 1 deletion lib/xml_json/aws_api/serializer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule XmlJson.AwsApi.Serializer do

alias XmlJson.SaxHandler

@spec serialize(map(), map()) :: {:ok, binary()}
@spec serialize(map(), map()) :: {:ok, binary()} | {:error, term()}
def serialize(object, opts) do
[{name, value}] = Map.to_list(object)
simple_form = to_simple_form(value, name, opts)
Expand Down
4 changes: 2 additions & 2 deletions lib/xml_json/badgerfish.ex
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ defmodule XmlJson.BadgerFish do
{:ok, "<alice>bob</alice>"}
"""
@spec serialize(map(), badgerfish_options()) :: {:ok, binary()}
@spec serialize(map(), badgerfish_options()) :: {:ok, binary()} | {:error, term()}
def serialize(object, opts \\ [])
def serialize(object, opts), do: Serializer.serialize(object, merge_default_options(opts))

Expand Down Expand Up @@ -63,7 +63,7 @@ defmodule XmlJson.BadgerFish do
{:ok, %{"alice" => %{"$" => "bob"}}}
"""
@spec deserialize(binary(), badgerfish_options()) :: {:ok, map()}
@spec deserialize(binary(), badgerfish_options()) :: {:ok, map()} | {:error, term()}
def deserialize(xml, opts \\ [])
def deserialize(xml, opts), do: Deserializer.deserialize(xml, merge_default_options(opts))

Expand Down
2 changes: 1 addition & 1 deletion lib/xml_json/badgerfish/deserializer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule XmlJson.BadgerFish.Deserializer do

alias XmlJson.SaxHandler

@spec deserialize(binary(), map()) :: {:ok, map()}
@spec deserialize(binary(), map()) :: {:ok, map()} | {:error, Saxy.ParseError.t()}
def deserialize(xml, opts) do
case SaxHandler.parse_string(xml) do
{:ok, element} ->
Expand Down
2 changes: 1 addition & 1 deletion lib/xml_json/badgerfish/serializer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule XmlJson.BadgerFish.Serializer do

alias XmlJson.SaxHandler

@spec serialize(map(), map()) :: {:ok, binary()}
@spec serialize(map(), map()) :: {:ok, binary()} | {:error, term()}
def serialize(object, opts) do
[{name, value}] = Map.to_list(object)
simple_form = to_simple_form(value, name, opts)
Expand Down
4 changes: 2 additions & 2 deletions lib/xml_json/parker.ex
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ defmodule XmlJson.Parker do
{:ok, "<alice>bob</alice>"}
"""
@spec serialize(map(), parker_options()) :: {:ok, binary()}
@spec serialize(map(), parker_options()) :: {:ok, binary()} | {:error, term()}
def serialize(object, opts \\ [])
def serialize(object, opts), do: Serializer.serialize(object, merge_default_options(opts))

Expand Down Expand Up @@ -64,7 +64,7 @@ defmodule XmlJson.Parker do
{:ok, %{"alice" => "bob"}}
"""
@spec deserialize(binary(), parker_options()) :: {:ok, map()}
@spec deserialize(binary(), parker_options()) :: {:ok, map()} | {:error, term()}
def deserialize(xml, opts \\ [])
def deserialize(xml, opts), do: Deserializer.deserialize(xml, merge_default_options(opts))

Expand Down
2 changes: 1 addition & 1 deletion lib/xml_json/parker/serializer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule XmlJson.Parker.Serializer do

alias XmlJson.SaxHandler

@spec serialize(map(), map()) :: {:ok, binary()}
@spec serialize(map(), map()) :: {:ok, binary()} | {:error, term()}
def serialize(object, opts) do
{name, value} = root_map_form(object, opts)
simple_form = to_simple_form(value, name)
Expand Down

0 comments on commit f64b5fa

Please sign in to comment.