-module(aws@internal@codec@xml).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/aws/internal/codec/xml.gleam").
-export([element/2, escape_text/1, escape_attr/1, element_with_attrs/3, empty_element/1, text/1, bool_text/1, int_text/1, float_text/1, blob_text/1, list_element/3, flat_list/2, map_entries/3, map_element/4, flat_map/4, list_element_ns/5, flat_list_ns/3, map_entries_ns/5, map_element_ns/7, flat_map_ns/7]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" XML encoder helpers for restXml / awsQuery / ec2Query bodies.\n"
" Minimum viable: element-per-member, text-content for primitives,\n"
" proper escaping of `<>&\"'`. Honours `@xmlName` overrides at the\n"
" call site (the emitter passes the resolved element name).\n"
"\n"
" The XML response decoder lives in\n"
" `src/aws/internal/codec/xml_decode.gleam` — kept separate because\n"
" it pulls in xmerl via FFI, which is heavier than the pure-string\n"
" encoder side.\n"
).
-file("src/aws/internal/codec/xml.gleam", 17).
?DOC(" `<Name>...</Name>` wrapper around inner content.\n").
-spec element(binary(), binary()) -> binary().
element(Name, Inner) ->
<<<<<<<<<<<<"<"/utf8, Name/binary>>/binary, ">"/utf8>>/binary,
Inner/binary>>/binary,
"</"/utf8>>/binary,
Name/binary>>/binary,
">"/utf8>>.
-file("src/aws/internal/codec/xml.gleam", 50).
?DOC(" Escape `<`, `>`, `&` in element text content.\n").
-spec escape_text(binary()) -> binary().
escape_text(S) ->
_pipe = S,
_pipe@1 = gleam@string:replace(_pipe, <<"&"/utf8>>, <<"&"/utf8>>),
_pipe@2 = gleam@string:replace(_pipe@1, <<"<"/utf8>>, <<"<"/utf8>>),
gleam@string:replace(_pipe@2, <<">"/utf8>>, <<">"/utf8>>).
-file("src/aws/internal/codec/xml.gleam", 61).
?DOC(
" Escape `&`, `<`, `>`, `\"`, and `'` in attribute values. AWS\n"
" service XML is double-quoted, so `'` doesn't strictly need\n"
" escaping, but the entity is harmless and keeps the encoder\n"
" quote-style agnostic.\n"
).
-spec escape_attr(binary()) -> binary().
escape_attr(S) ->
_pipe = S,
_pipe@1 = escape_text(_pipe),
_pipe@2 = gleam@string:replace(_pipe@1, <<"\""/utf8>>, <<"""/utf8>>),
gleam@string:replace(_pipe@2, <<"'"/utf8>>, <<"'"/utf8>>).
-file("src/aws/internal/codec/xml.gleam", 24).
?DOC(
" `<Name attr1=\"v1\" attr2=\"v2\">inner</Name>`. Attribute values are\n"
" escaped the same way as text content; attribute names are passed\n"
" verbatim and assumed to be safe (Smithy member names).\n"
).
-spec element_with_attrs(binary(), list({binary(), binary()}), binary()) -> binary().
element_with_attrs(Name, Attrs, Inner) ->
Attr_str = case Attrs of
[] ->
<<""/utf8>>;
_ ->
gleam@list:fold(
Attrs,
<<""/utf8>>,
fun(Acc, P) ->
{K, V} = P,
<<<<<<<<<<Acc/binary, " "/utf8>>/binary, K/binary>>/binary,
"=\""/utf8>>/binary,
(escape_attr(V))/binary>>/binary,
"\""/utf8>>
end
)
end,
<<<<<<<<<<<<<<"<"/utf8, Name/binary>>/binary, Attr_str/binary>>/binary,
">"/utf8>>/binary,
Inner/binary>>/binary,
"</"/utf8>>/binary,
Name/binary>>/binary,
">"/utf8>>.
-file("src/aws/internal/codec/xml.gleam", 41).
?DOC(" `<Name/>` — short form for empty elements.\n").
-spec empty_element(binary()) -> binary().
empty_element(Name) ->
<<<<"<"/utf8, Name/binary>>/binary, "/>"/utf8>>.
-file("src/aws/internal/codec/xml.gleam", 45).
-spec text(binary()) -> binary().
text(Value) ->
escape_text(Value).
-file("src/aws/internal/codec/xml.gleam", 69).
?DOC(" Format helpers for primitive members.\n").
-spec bool_text(boolean()) -> binary().
bool_text(B) ->
case B of
true ->
<<"true"/utf8>>;
false ->
<<"false"/utf8>>
end.
-file("src/aws/internal/codec/xml.gleam", 77).
-spec int_text(integer()) -> binary().
int_text(N) ->
erlang:integer_to_binary(N).
-file("src/aws/internal/codec/xml.gleam", 80).
-spec float_text(float()) -> binary().
float_text(F) ->
aws_ffi:float_short(F).
-file("src/aws/internal/codec/xml.gleam", 84).
?DOC(
" Base64-encode a blob value for XML body inclusion. S3 uses base64\n"
" for binary fields inside XML bodies (Content-MD5, ChecksumSHA256).\n"
).
-spec blob_text(bitstring()) -> binary().
blob_text(B) ->
gleam_stdlib:base64_encode(B, true).
-file("src/aws/internal/codec/xml.gleam", 92).
?DOC(
" Build a list element with each entry as `<member_name>value</member_name>`\n"
" children. The wrapper element comes from the list shape's name; the\n"
" per-entry element name comes from the list member's `@xmlName` (the\n"
" emitter passes both).\n"
).
-spec list_element(binary(), binary(), list(binary())) -> binary().
list_element(Wrapper, Member_name, Entries) ->
Inner = gleam@list:fold(
Entries,
<<""/utf8>>,
fun(Acc, Entry_inner) ->
<<Acc/binary, (element(Member_name, Entry_inner))/binary>>
end
),
element(Wrapper, Inner).
-file("src/aws/internal/codec/xml.gleam", 106).
?DOC(
" Same as `list_element` but for `@xmlFlattened` lists — no\n"
" wrapper element; entries become direct siblings.\n"
).
-spec flat_list(binary(), list(binary())) -> binary().
flat_list(Member_name, Entries) ->
gleam@list:fold(
Entries,
<<""/utf8>>,
fun(Acc, Entry_inner) ->
<<Acc/binary, (element(Member_name, Entry_inner))/binary>>
end
).
-file("src/aws/internal/codec/xml.gleam", 127).
?DOC(
" Just the `<entry>...</entry>` siblings of a map, no wrapper.\n"
" Used for nested maps — the outer map's `<value>` element wraps\n"
" the inner map's entries directly.\n"
).
-spec map_entries(binary(), binary(), gleam@dict:dict(binary(), binary())) -> binary().
map_entries(Key_name, Value_name, Entries) ->
gleam@dict:fold(
Entries,
<<""/utf8>>,
fun(Acc, K, V) ->
<<Acc/binary,
(element(
<<"entry"/utf8>>,
<<(element(Key_name, escape_text(K)))/binary,
(element(Value_name, V))/binary>>
))/binary>>
end
).
-file("src/aws/internal/codec/xml.gleam", 115).
?DOC(
" Build a map element: each entry becomes `<entry><key>K</key><value>V</value></entry>`\n"
" inside a wrapper. Smithy default uses `entry` / `key` / `value` —\n"
" `@xmlName` overrides land in the caller.\n"
).
-spec map_element(
binary(),
binary(),
binary(),
gleam@dict:dict(binary(), binary())
) -> binary().
map_element(Wrapper, Key_name, Value_name, Entries) ->
element(Wrapper, map_entries(Key_name, Value_name, Entries)).
-file("src/aws/internal/codec/xml.gleam", 147).
?DOC(
" `@xmlFlattened` map: each entry becomes a top-level\n"
" `<member_name><key>K</key><value>V</value></member_name>` block\n"
" — no outer wrapper, no `<entry>` tag. The caller's containing\n"
" element provides the sequencing. `value_name` is the key / value\n"
" inner-element name (`\"key\"` / `\"value\"` by default; `@xmlName`\n"
" overrides land in the caller).\n"
).
-spec flat_map(
binary(),
binary(),
binary(),
gleam@dict:dict(binary(), binary())
) -> binary().
flat_map(Member_name, Key_name, Value_name, Entries) ->
gleam@dict:fold(
Entries,
<<""/utf8>>,
fun(Acc, K, V) ->
<<Acc/binary,
(element(
Member_name,
<<(element(Key_name, escape_text(K)))/binary,
(element(Value_name, V))/binary>>
))/binary>>
end
).
-file("src/aws/internal/codec/xml.gleam", 167).
?DOC(
" `list_element` variant that carries member-level XML namespace\n"
" attributes. `wrapper_attrs` go on the outer wrapping element;\n"
" `member_attrs` go on every per-entry wrapping. Either list may\n"
" be empty, in which case the corresponding wrapper renders\n"
" without attributes — equivalent to `list_element` in that case.\n"
).
-spec list_element_ns(
binary(),
list({binary(), binary()}),
binary(),
list({binary(), binary()}),
list(binary())
) -> binary().
list_element_ns(Wrapper, Wrapper_attrs, Member_name, Member_attrs, Entries) ->
Inner = gleam@list:fold(
Entries,
<<""/utf8>>,
fun(Acc, Entry_inner) ->
<<Acc/binary,
(element_with_attrs(Member_name, Member_attrs, Entry_inner))/binary>>
end
),
element_with_attrs(Wrapper, Wrapper_attrs, Inner).
-file("src/aws/internal/codec/xml.gleam", 183).
?DOC(
" `flat_list` variant with namespace attributes on every emitted\n"
" member element. Empty `member_attrs` collapses to a bare element.\n"
).
-spec flat_list_ns(binary(), list({binary(), binary()}), list(binary())) -> binary().
flat_list_ns(Member_name, Member_attrs, Entries) ->
gleam@list:fold(
Entries,
<<""/utf8>>,
fun(Acc, Entry_inner) ->
<<Acc/binary,
(element_with_attrs(Member_name, Member_attrs, Entry_inner))/binary>>
end
).
-file("src/aws/internal/codec/xml.gleam", 216).
?DOC(
" `map_entries` variant with namespace attributes on the key /\n"
" value wrappers. Used for nested maps and as the body of\n"
" `map_element_ns`.\n"
).
-spec map_entries_ns(
binary(),
list({binary(), binary()}),
binary(),
list({binary(), binary()}),
gleam@dict:dict(binary(), binary())
) -> binary().
map_entries_ns(Key_name, Key_attrs, Value_name, Value_attrs, Entries) ->
gleam@dict:fold(
Entries,
<<""/utf8>>,
fun(Acc, K, V) ->
<<Acc/binary,
(element(
<<"entry"/utf8>>,
<<(element_with_attrs(Key_name, Key_attrs, escape_text(K)))/binary,
(element_with_attrs(Value_name, Value_attrs, V))/binary>>
))/binary>>
end
).
-file("src/aws/internal/codec/xml.gleam", 197).
?DOC(
" `map_element` variant with namespace attributes on the outer\n"
" wrapper plus the key / value wrappers. The intermediate\n"
" `<entry>` wrapper is unattributed (Smithy doesn't expose a\n"
" trait for it).\n"
).
-spec map_element_ns(
binary(),
list({binary(), binary()}),
binary(),
list({binary(), binary()}),
binary(),
list({binary(), binary()}),
gleam@dict:dict(binary(), binary())
) -> binary().
map_element_ns(
Wrapper,
Wrapper_attrs,
Key_name,
Key_attrs,
Value_name,
Value_attrs,
Entries
) ->
element_with_attrs(
Wrapper,
Wrapper_attrs,
map_entries_ns(Key_name, Key_attrs, Value_name, Value_attrs, Entries)
).
-file("src/aws/internal/codec/xml.gleam", 235).
?DOC(
" `flat_map` variant with namespace attributes on the repeated\n"
" member wrappers and on the key / value wrappers inside.\n"
).
-spec flat_map_ns(
binary(),
list({binary(), binary()}),
binary(),
list({binary(), binary()}),
binary(),
list({binary(), binary()}),
gleam@dict:dict(binary(), binary())
) -> binary().
flat_map_ns(
Member_name,
Member_attrs,
Key_name,
Key_attrs,
Value_name,
Value_attrs,
Entries
) ->
gleam@dict:fold(
Entries,
<<""/utf8>>,
fun(Acc, K, V) ->
<<Acc/binary,
(element_with_attrs(
Member_name,
Member_attrs,
<<(element_with_attrs(Key_name, Key_attrs, escape_text(K)))/binary,
(element_with_attrs(Value_name, Value_attrs, V))/binary>>
))/binary>>
end
).