SefazNfe.XML (sefaz_nfe v0.1.0)

Copy Markdown View Source

Reading side of the SEFAZ XML, on :xmerl.

Safety

The body arrives over the network, so parsing is hardened before :xmerl sees it. A DTD is rejected outright: SEFAZ never sends one, and accepting it is what opens both XXE and entity expansion (billion laughs). :xmerl has no budget for either, so refusing the construct is the defence rather than limiting it. External fetches are stubbed as a second layer, and a malformed body is an error rather than a crash — the network is allowed to be hostile.

Encoding

The body is handed to :xmerl as raw bytes, not as a decoded charlist. SEFAZ declares encoding="utf-8" and its messages are Portuguese — every rejection carries accents — so :xmerl must do the decoding itself. Passing already-decoded codepoints makes it decode twice and reject the document.

Scanning is namespace conformant, which is what populates the namespace axis SefazNfe.XML.C14N needs to canonicalise a subtree for signing.

Reading

text/2 and attribute/3 take a local element name and ignore namespace prefixes. SEFAZ responses arrive prefixed differently per UF and per service, and matching on the local name is what keeps one parser working across all of them.

Summary

Functions

Every element whose local name is name.

Value of attribute attr on the first element named name.

The first element whose local name is name, as an :xmerl record.

Text of name as an integer, or nil when absent or not numeric.

Attribute attr on element itself, without searching its descendants.

Text of element itself, without searching its descendants.

Parses body into an :xmerl document.

Text content of the first element whose local name is name.

Types

doc()

@type doc() :: tuple()

Functions

all(doc, name)

@spec all(doc(), String.t()) :: [doc()]

Every element whose local name is name.

attribute(doc, name, attr)

@spec attribute(doc(), String.t(), String.t()) :: String.t() | nil

Value of attribute attr on the first element named name.

element(doc, name)

@spec element(doc(), String.t()) :: doc() | nil

The first element whose local name is name, as an :xmerl record.

integer(doc, name)

@spec integer(doc(), String.t()) :: integer() | nil

Text of name as an integer, or nil when absent or not numeric.

own_attribute(element, attr)

@spec own_attribute(doc(), String.t()) :: String.t() | nil

Attribute attr on element itself, without searching its descendants.

own_text(element)

@spec own_text(doc()) :: String.t() | nil

Text of element itself, without searching its descendants.

parse(body)

@spec parse(binary()) :: {:ok, doc()} | {:error, {:xml, atom()}}

Parses body into an :xmerl document.

Returns {:error, {:xml, :dtd_forbidden}} for a body carrying a DTD and {:error, {:xml, :malformed}} when :xmerl cannot read it.

text(doc, name)

@spec text(doc(), String.t()) :: String.t() | nil

Text content of the first element whose local name is name.