Vendored copy of xmerl_c14n (DoggettCK/xmerl_c14n on Hex, derived
from esaml's Erlang implementation).
Functions for performing XML canonicalization (c14n), as specified at http://www.w3.org/TR/xml-c14n.
Why vendored
The Hex package (last release Sep 2019) crashes on OTP 28 when an
unprefixed attribute carries [] in its namespace field rather
than {:xmlNamespace, [], []}. We vendor + patch rather than
carrying a broken dependency.
Local edits vs. upstream Hex 0.2.0 (BSD-2-Clause)
- Module renamed
XmerlC14n→SignCore.XML.C14n.XmerlC14n. do_canonical_name/3gains a clause for non-:xmlNamespacenamespace fields — returns the bare local name (exc-c14n's rule for unprefixed attributes living in no namespace).
Original copyright in LICENSE.md in this directory. The above
patches are © 2026 the pkcs11ex maintainers, BSD-2-Clause-compatible.
Summary
Functions
Given an xmerl XML tuple (element/attribute/etc...) or string
representation of XML, returns the canonical binary version of the XML it
represents.
Given an xmerl XML tuple (element/attribute/etc...) or string
representation of XML, returns the canonical binary version of the XML it
represents.
Functions
@spec canonicalize(entity :: xml_type() | String.t()) :: {:ok, String.t()} | {:error, {:failed_canonicalization, term()}}
Given an xmerl XML tuple (element/attribute/etc...) or string
representation of XML, returns the canonical binary version of the XML it
represents.
Returns either {:ok, String.t()} if canonicalized successfully, or
{:error, {:failed_canonicalization, term}} if canonicalization failed.
If the preserve_comments argument is true, preserves comments in the output. Any
namespace prefixes listed in inclusive_namespaces will be left as they are and not
modified during canonicalization.
# Given xml
<!DOCTYPE doc [<!ATTLIST e9 attr CDATA "default">]>
<doc>
<e1 />
<e2 ></e2>
<e3 name = "elem3" id="elem3" />
<e4 name="elem4" id="elem4" ></e4>
<e5 a:attr="out" b:attr="sorted" attr2="all" attr="I'm"
xmlns:b="http://www.ietf.org"
xmlns:a="http://www.w3.org"
xmlns="http://example.org"/>
<e6 xmlns="" xmlns:a="http://www.w3.org">
<e7 xmlns="http://www.ietf.org">
<e8 xmlns="" xmlns:a="http://www.w3.org">
<e9 xmlns="" xmlns:a="http://www.ietf.org"/>
</e8>
</e7>
</e6>
</doc>
iex> {:ok, canonicalized_xml} = XmerlC14n.canonicalize(xml)
iex> IO.puts(canonicalized_xml)
<doc>
<e1></e1>
<e2></e2>
<e3 id="elem3" name="elem3"></e3>
<e4 id="elem4" name="elem4"></e4>
<e5 xmlns="http://example.org" xmlns:a="http://www.w3.org" xmlns:b="http://www.ietf.org" attr="I'm" attr2="all" b:attr="sorted" a:attr="out"></e5>
<e6>
<e7 xmlns="http://www.ietf.org">
<e8 xmlns="">
<e9></e9>
</e8>
</e7>
</e6>
</doc>
Given an xmerl XML tuple (element/attribute/etc...) or string
representation of XML, returns the canonical binary version of the XML it
represents.
Returns either String.t() if canonicalized successfully, or raises an
ArgumentError if canonicalization failed.
If the preserve_comments argument is true, preserves comments in the output. Any
namespace prefixes listed in inclusive_namespaces will be left as they are and not
modified during canonicalization.
# Given xml
<!DOCTYPE doc [<!ATTLIST e9 attr CDATA "default">]>
<doc>
<e1 />
<e2 ></e2>
<e3 name = "elem3" id="elem3" />
<e4 name="elem4" id="elem4" ></e4>
<e5 a:attr="out" b:attr="sorted" attr2="all" attr="I'm"
xmlns:b="http://www.ietf.org"
xmlns:a="http://www.w3.org"
xmlns="http://example.org"/>
<e6 xmlns="" xmlns:a="http://www.w3.org">
<e7 xmlns="http://www.ietf.org">
<e8 xmlns="" xmlns:a="http://www.w3.org">
<e9 xmlns="" xmlns:a="http://www.ietf.org"/>
</e8>
</e7>
</e6>
</doc>
iex> XmerlC14n.canonicalize!(xml) |> IO.puts
<doc>
<e1></e1>
<e2></e2>
<e3 id="elem3" name="elem3"></e3>
<e4 id="elem4" name="elem4"></e4>
<e5 xmlns="http://example.org" xmlns:a="http://www.w3.org" xmlns:b="http://www.ietf.org" attr="I'm" attr2="all" b:attr="sorted" a:attr="out"></e5>
<e6>
<e7 xmlns="http://www.ietf.org">
<e8 xmlns="">
<e9></e9>
</e8>
</e7>
</e6>
</doc>