xmerl_sax_parser(3)
β¨ NAME β¨
xmerl_sax_parser β it's the XML SAX parser API, bestie π
πΈ DESCRIPTION πΈ
okay so picture this: it's a SAX parser for XML, and what it does is it sends the events through a callback interface π like, the parser walks the XML and every time something happens it just yells it at your callbacks. main character energy fr fr.
SAX stands for Simple API for XML β yes the acronym really spells SAX and not something cute, we work with what we've got π
ngl the lore is kinda iconic: SAX was originally a Java-only API π like, exclusively Java, nobody else invited. But it was the first widely adopted API for XML in Java, and from there it became a de facto standard β the way that a thing just becomes the standard by everyone using it?? obsessed π¦
and because it got so big, there are now versions of it for several programming language environments other than Java π so it broke out of the Java-only era and went multi-language. we love an inclusive glow-up β¨
π not me explaining SAX like it's tea but genuinely that's the whole vibe check here: events β callbacks, Java origin story, de facto standard, now everywhere.
more coming, don't go anywhere π«Ά
π DATA TYPES π
Okay bestie, this is the part where we meet all the little building blocks π§±β¨ Every single one of them, no skipping, we're being thorough girlies today.
continuation_fun()
continuation_fun() ::
fun((continuation_state()) ->
{NewBytes :: binary() | list(),
continuation_state()}).
This is the callback function/0 that gets pinged whenever the parser runs out of input data. π
If the function literally cannot get its hands on more input, it hands back an empty list or an empty binary (which one depends on what you started the input as in stream/2). Any other kind of error gets handled through exceptions. If the continuation function hits a fatal error, use throw/1 to fling this tuple:
{Tag = atom(), Reason = string()}
<Tag> is an atom that IDs the functional entity sending the exception, and <Reason> is a string describing what actually went wrong. Tag + Reason, the iconic duo π
continuation_state()
continuation_state() :: term().
event()
event() ::
startDocument | endDocument |
{startPrefixMapping, Prefix :: string(), Uri :: string()} |
{endPrefixMapping, Prefix :: string()} |
{startElement,
Uri :: string(),
LocalName :: string(),
QualifiedName :: string(),
Attributes :: string()} |
{endElement,
Uri :: string(),
LocalName :: string(),
QualifiedName :: string()} |
{characters, string()} |
{ignorableWhitespace, string()} |
{processingInstruction, Target :: string(), Data :: string()}
|
{comment, string()} |
startCDATA | endCDATA |
{startDTD,
Name :: string(),
PublicId :: string(),
SystemId :: string()} |
endDTD |
{startEntity, SysId :: string()} |
{endEntity, SysId :: string()} |
{elementDecl, Name :: string(), Model :: string()} |
{attributeDecl,
ElementName :: string(),
AttributeName :: string(),
Type :: string(),
Mode :: string(),
Value :: string()} |
{internalEntityDecl, Name :: string(), Value :: string()} |
{externalEntityDecl,
Name :: string(),
PublicId :: string(),
SystemId :: string()} |
{unparsedEntityDecl,
Name :: string(),
PublicId :: string(),
SystemId :: string(),
Ndata :: string()} |
{notationDecl,
Name :: string(),
PublicId :: string(),
SystemId :: string()}.
These are the SAX events that get slid over to you through the event callback. Here's the whole roster, one by one ππ
startDocumentβ You're getting notified that the document is beginning. The SAX parser sends this event exactly once, before any other event callback fires. One and done bestie πendDocumentβ Notification that the document is done. The SAX parser sends this exactly once, and it's the last event of the whole parse. Closing time π{startPrefixMapping, Prefix, Uri}β Starts the scope of a prefix-to-URI Namespace mapping. Heads up though β start/endPrefixMapping events are not guaranteed to be properly nested relative to each other. AllstartPrefixMappingevents show up immediately before the matchingstartElementevent, and allendPrefixMappingevents show up immediately after the matchingendElementevent, but past that their order is not guaranteed at all. Also, there will be no start/endPrefixMapping events for the"xml"prefix, because it's predeclared and immutable. It's giving untouchable π{endPrefixMapping, Prefix}β Ends the scope of a prefix-to-URI mapping.{startElement, Uri, LocalName, QualifiedName, Attributes}β Notification that an element is starting. The Parser sends this at the beginning of every single element in the XML document, and there will be a matchingendElementfor everystartElement(even when the element is empty!). All of the element's content gets reported in order, before the correspondingendElement. Fully accounted for, no cap.{endElement, Uri, LocalName, QualifiedName}β Notification that an element is ending. The SAX parser sends this at the end of every element in the XML document, and everyendElementhas a matchingstartElement(again, even when the element is empty). Symmetry, slay β¨{characters, string()}β Notification of character data.{ignorableWhitespace, string()}β Notification of ignorable whitespace sitting in element content.{processingInstruction, Target, Data}β Notification of a processing instruction. The Parser sends this once for every processing instruction it finds β and note that processing instructions can show up before or after the main document element. They roam free π¦{comment, string()}β Reports an XML comment anywhere in the document, both inside and outside of the document element.startCDATAβ Reports the start of a CDATA section. The actual contents of the CDATA section get reported through the regularcharactersevent.endCDATAβ Reports the end of a CDATA section.{startDTD, Name, PublicId, SystemId}β Reports the start of DTD declarations, i.e. the start of theDOCTYPEdeclaration. If the document has noDOCTYPEdeclaration, this event simply won't be sent. πendDTDβ Reports the end of DTD declarations, i.e. the end of theDOCTYPEdeclaration.{startEntity, SysId}β Reports the beginning of some internal and external XML entities.{endEntity, SysId}β Reports the end of an entity.{elementDecl, Name, Model}β Reports an element type declaration. The content model is either the string"EMPTY", the string"ANY", or a parenthesised group optionally followed by an occurrence indicator. The model gets normalized so all parameter entities are fully resolved and all whitespace is removed, and it will include the enclosing parentheses. Any further normalization (like removing redundant parentheses or simplifying occurrence indicators) is left to the discretion of the parser.{attributeDecl, ElementName, AttributeName, Type, Mode, Value}β Reports an attribute type declaration.{internalEntityDecl, Name, Value}β Reports an internal entity declaration.{externalEntityDecl, Name, PublicId, SystemId}β Reports a parsed external entity declaration.{unparsedEntityDecl, Name, PublicId, SystemId, Ndata}β Notification of an unparsed entity declaration event.{notationDecl, Name, PublicId, SystemId}β Notification of a notation declaration event.
event_fun()
event_fun() ::
fun((event(), event_location(), event_state()) ->
event_state()).
This is the callback function/0 that fires for every. single. event the parser sends. π€ Obsessed with the dedication tbh.
Error handling here goes through exceptions. Use throw/1 to fling this tuple:
{Tag = atom(), Reason = string()}
...if the application hits a fatal error. <Tag> is an atom identifying the functional entity that sends the exception, and <Reason> is a string describing the problem. π
event_location()
event_location() ::
{CurrentLocation :: string(),
Entityname :: string(),
LineNo :: integer()}.
event_state()
event_state() :: term().
latin1_binary()
latin1_binary() :: unicode:latin1_binary().
A binary with characters encoded in iso-latin-1. π
options()
options() ::
[{continuation_fun, continuation_fun()} |
{continuation_state, continuation_state()} |
{event_fun, event_fun()} |
{event_state, event_state()} |
{file_type, normal | dtd} |
{encoding,
utf | {utf16, big} | {utf16, little} | latin1 | list} |
skip_external_dtd | disallow_entities |
{entity_recurse_limit, non_neg_integer()} |
{external_entities, all | file | none} |
{fail_undeclared_ref, boolean()} |
{discard_ws_before_xml_document, boolean()}].
These are the options used to customize how the parser behaves. The full list of possible options is right here bestie, don't scroll past π
{continuation_fun, ContinuationFun}β <ContinuationFun> is the callback function that decides what to do when the parser runs into EOF before the document is complete.{continuation_state, ContinuationState}β State that's reachable inside the continuation callback function.{event_fun, EventFun}β <EventFun> is the callback function for parser events.{event_state, EventState}β State that's reachable inside the event callback function.{file_type, FileType}β A flag that tells the parser whether it's parsing a DTD or a normal XML file. Default isnormal.{encoding, Encoding}β Sets the default character set to use. Default isutf, meaning UTF-8. This character set is used only if it isn't explicitly given by the XML document itself.skip_external_dtdβ Skips the external DTD while parsing. This option is the same as{external_entities, none}and{fail_undeclared_ref, false}, except it applies just to the DTD.disallow_entitiesβ Implies that parsing fails if anENTITYdeclaration is found. Big yikes energy, do not pass go.{entity_recurse_limit, N}β Sets how many levels of recursion are allowed for entities. Default is3levels.{external_entities, Allowed}β Sets which types of external entities are allowed; if it's not allowed, it just gets skipped. Default isnone.{fail_undeclared_ref, Boolean}β Decides how the parser behaves when an undeclared reference is found. Can be handy if you've turned off external entities so that an external DTD isn't parsed. Default istrue.{discard_ws_before_xml_document, Boolean}β Discards whitespace before the xml tag instead of returning a fatal error. Default isfalse. π«Ά
unicode_binary()
unicode_binary() :: binary().
A binary with characters encoded in UTF-8 or UTF-16. π
unicode_char()
unicode_char() :: char().
An integer representing a valid unicode codepoint. β
β¨ FUNCTIONS β¨
okay bestie, these are the two functions you'll actually call β and yes, they're both iconic π
file(Name, Options)
file(Name, Options) -> {ok, EventState, Rest} | ErrorOrUserReturn
when
Name :: file:filename(),
Options :: options(),
EventState :: event_state(),
Rest :: unicode_binary() | latin1_binary(),
ErrorOrUserReturn ::
{Tag, Location, Reason, EndTags, EventState} |
{error, {Name, Reason}},
Tag :: fatal_error | atom(),
Location :: event_location(),
Reason :: term(),
EndTags :: term().
This one parses a file that contains an XML document, bestie. It uses a default continuation function to read the file in blocks β so like, it's reading your file in cute little chunks, no cap. π«Ά
The return vibe is either {ok, EventState, Rest} or ErrorOrUserReturn, and all the type details are right there in the when clause above. Periodt. π
stream(Xml, Options)
stream(Xml, Options) -> {ok, EventState, Rest} | ErrorOrUserReturn
when
Xml ::
unicode_binary() |
latin1_binary() |
[unicode_char],
Options :: options(),
EventState :: event_state(),
Rest :: unicode_binary() | latin1_binary(),
ErrorOrUserReturn ::
{Tag, Location, Reason, EndTags, EventState},
Tag :: fatal_error | atom(),
Location :: event_location(),
Reason :: term(),
EndTags :: term().
This one parses a stream containing an XML document. That's it, that's the function. Slay. β¨
no date on this footer, but the source/version energy is immaculate anyway.
shoutout to Ericsson AB, xmerl 2.2, and the whole xmerl_sax_parser(3) manual page for the footer vibes. bye bestie, go parse something gorgeous π¦π
π¦ where this page comes from
- nixos 26.05: erlang 29.1.2
- nixpkgs unstable: erlang 29.1.2
- ubuntu stonking: erlang-doc 1:29.0.6+dfsg-1 Β· Apache-2.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms