Current section
Files
Jump to
Current section
Files
lib/soapex/xsd.ex
defmodule Soapex.Xsd do
@moduledoc false
import SweetXml
import Soapex.Util
@spec get_schema(String.t()) :: map
def get_schema(schema) do
if schema == nil, do: throw("Schema is nil")
get_schema_internal(schema)
end
defp get_schema_internal(schema_el) do
%{
target_ns: schema_el |> ns_xpath(~x"@targetNamespace"so) || schema_el |> ns_xpath(~x"@namespace"so),
attribute_form_default: get_qualified_unqualified(schema_el, "attributeFormDefault"),
element_form_default: get_qualified_unqualified(schema_el, "elementFormDefault"),
elements: get_elements(schema_el),
complex_types: get_complex_types(schema_el),
simple_types: get_simple_types(schema_el),
attribute_groups: get_attribute_groups(schema_el)
}
end
defp get_qualified_unqualified(schema_el, att_name) do
case schema_el |> ns_xpath(~x"@#{att_name}"so) do
"" ->
:unqualified
nil ->
:unqualified
"unqualified" ->
:unqualified
"qualified" ->
:qualified
end
end
defp get_simple_types(schema_el) do
schema_el
|> ns_xpath(~x"./xsd:simpleType"l)
|> map_simple_types
|> Enum.map(&no_nil_or_empty_value/1)
end
defp get_simple_type(node) do
name =
node
|> ns_xpath(~x".",
name: ~x"./@name"s,
restriction: ~x"." |> transform_by(&get_restriction/1),
union: ~x"." |> transform_by(&get_union/1)
)
name
|> no_nil_or_empty_value
end
defp get_union(node) do
node
|> ns_xpath(~x"./xsd:union"oe,
member_types: ~x"@memberTypes",
simple_types: ~x"./xsd:simpleType"l |> transform_by(&map_simple_types/1)
)
|> no_nil_or_empty_value
end
defp map_simple_types(simple_type_els) do
simple_type_els
|> Enum.map(&get_simple_type/1)
end
defp get_restriction(node) do
restriction =
node
|> ns_xpath(~x"./xsd:restriction"oe,
base: ~x"./@base"s,
length: ~x"./xsd:length/@value"s,
min_length: ~x"./xsd:minLength/@value"s,
max_length: ~x"./xsd:maxLength/@value"s,
min_exclusive: ~x"./xsd:minExclusive/@value"s,
max_exclusive: ~x"./xsd:maxExclusive/@value"s,
min_inclusive: ~x"./xsd:minInclusive/@value"s,
max_inclusive: ~x"./xsd:maxInclusive/@value"s,
total_digits: ~x"./xsd:totalDigits/@value"s,
fraction_digits: ~x"./xsd:fractionDigits/@value"s,
enumeration: ~x"./xsd:enumeration"l,
white_space: ~x"./xsd:whiteSpace/@value"s,
pattern: ~x"./xsd:pattern/@value"s
)
|> no_nil_or_empty_value
case restriction do
nil ->
nil
_ ->
restriction
|> Map.put(:enumeration, get_enumeration(restriction[:enumeration]))
|> Map.put(:base, type(restriction[:base]))
|> no_nil_or_empty_value
end
end
defp get_enumeration(nil), do: nil
defp get_enumeration(enums) do
enums
|> ensure_list
|> Enum.map(fn node -> ns_xpath(node, ~x"./@value"s) end)
end
defp get_attribute_groups(parent) do
parent
|> ns_xpath(~x"./xsd:attributeGroup"l)
|> map_attribute_group
end
defp map_attribute_group(group_els) do
group_els
|> Enum.map(&get_attribute_group/1)
end
defp get_attribute_group(group_el) do
name =
group_el
|> ns_xpath(~x".",
name: ~x"./@name"os,
ref: ~x"./@ref"os,
any_attribute: ~x"./xsd:anyAttribute"oe
)
name
|> no_nil_or_empty_value
end
# defp get_any_attribute(nil), do: nil
# defp get_any_attribute(any_att_el) do
# any_att_el
# |>
# end
@spec get_complex_types(String.t()) :: list(Map.t())
defp get_complex_types(schema_el) do
schema_el
|> ns_xpath(~x"./xsd:complexType"l)
|> Enum.map(fn node -> get_complex_type(node) end)
end
defp get_complex_type(nil), do: nil
defp get_complex_type(node) do
name = node |> ns_xpath(~x".", name: ~x"./@name"s)
elements =
node
|> ns_xpath(~x"./xsd:sequence | ./xsd:choice | ./xsd:all")
|> get_element_list
type =
case node |> ns_xpath(~x"./xsd:sequence | ./xsd:choice | ./xsd:all") do
nil -> :empty
el -> get_element_name(el)
end
name
|> Map.merge(%{elements: elements, type: type})
|> no_nil_or_empty_value
end
defp get_element_name(el) do
{_, _, _, {_, name}, _, _, _, _, _, _, _, _} = el
:erlang.list_to_atom(name)
end
defp get_element_list(parent) do
case parent do
nil ->
nil
_ ->
parent
|> ns_xpath(~x"./xsd:element"l)
|> Enum.map(fn node -> get_element(node) end)
end
end
@spec get_elements(String.t()) :: list(Map.t())
defp get_elements(schema_el) do
schema_el
|> ns_xpath(~x"./xsd:element"l)
|> Enum.map(fn node -> get_element(node) end)
end
defp get_element(node) do
header =
node
|> ns_xpath(~x".",
name: ~x"./@name"s,
ref: ~x"./@ref"s |> transform_by(&type/1),
type: ~x"./@type"s |> transform_by(&type/1),
nillable: ~x"./@nillable"os |> transform_by(&boolean/1),
min_occurs: ~x"./@minOccurs"oi,
max_occurs: ~x"./@maxOccurs"os,
complex_type: ~x".//xsd:complexType"oe |> transform_by(&get_complex_type/1)
)
header
|> no_nil_or_empty_value
end
defp boolean(""), do: nil
defp boolean(nil), do: nil
defp boolean("false"), do: false
defp boolean("true"), do: true
end