Parser Events: Tags and Attributes
Relevant source files
The following files were used as context for generating this wiki page:
htmlparser2 is a fast, forgiving HTML/XML parser that operates via a callback-based architecture. The core of its functionality revolves around identifying structural elements such as tags and attributes within a stream of data and emitting specific events to a handler. This event-driven approach allows for high-performance processing with minimal memory allocation, as the parser does not build a full DOM tree by default unless used with a DomHandler.
The system distinguishes between low-level tokenization (identifying raw characters and sequences) and high-level parsing (maintaining element stacks, handling implicit tags, and managing namespaces). This separation ensures that the Parser can handle complex HTML behaviors like auto-closing paragraphs or foreign contexts (SVG/MathML) while the Tokenizer remains focused on efficient character state transitions.
Sources: README.md:16-20, src/Parser.ts:327-350, src/Tokenizer.ts:245-270
Tag Event Architecture
The parser emits events for tag lifecycles, including the start of a tag name, the completion of the opening tag (after attributes), and the closing of a tag. The Parser class implements the Callbacks interface from the Tokenizer to bridge raw tokens into semantic HTML events.
Lifecycle of a Tag Event
When the tokenizer encounters a < followed by a valid tag start character, it transitions through several states to identify the tag name and its boundaries.
The sequence of calls between the Tokenizer, Parser, and the user-provided Handler during tag discovery.
Sources: src/Parser.ts:468-525, src/Tokenizer.ts:634-650
Core Tag Methods
emitOpenTag(name): Handles the logic for opening a tag, including checking for implicit closures (e.g., a<li>closing a previous<li>) and pushing the tag onto the internal stack.popElement(implied): Removes the top element from the stack and maintains the foreign context stack for SVG/MathML.readTagName(start, end): Extracts the tag name from the buffer, applying case sensitivity rules based onxmlModeandlowerCaseTagsoptions.
Sources: src/Parser.ts:473-510, src/Parser.ts:549-560
Attribute Processing
Attributes are parsed as a sub-sequence of the opening tag. The parser maintains a temporary attribs object to aggregate all key-value pairs before emitting the final onopentag event.
Attribute Events Table
| Event | Logic | Source |
|---|---|---|
onattribname | Captures the attribute key. Supports lowercasing via lowerCaseAttributeNames. | src/Parser.ts:577-584 |
onattribdata | Accumulates attribute value chunks. | src/Parser.ts:586-590 |
onattribentity | Decodes entities (e.g., &) within attribute values. | src/Parser.ts:592-595 |
onattribend | Finalizes the attribute. Maps QuoteType to ", ', null (unquoted), or undefined (no value). | src/Parser.ts:597-616 |
Quote Type Management
The Tokenizer identifies the quoting style used for attributes, which is then passed to the handler:
export enum QuoteType {
NoValue = 0,
Unquoted = 1,
Single = 2,
Double = 3,
}
Sources: src/Tokenizer.ts:133-138, src/Parser.ts:602-612
Implicit Tag Logic and HTML Mode
In HTML mode (xmlMode: false), the parser implements specific "forgiving" behaviors defined by the HTML specification. This includes auto-closing tags when certain other tags are opened.
Open-Implies-Close Relationships
The parser uses an openImpliesClose map to determine if an incoming tag should force the closure of the current stack top. For example:
- A
<li>tag will close an existing open<li>. - A
<tr>tag will close an opentr,th, ortd. - A
<p>tag will close an openpor various block-level elements.
Logic flow for handling implicit tag closures in HTML mode.
Sources: src/Parser.ts:40-78, src/Parser.ts:490-495
Void Elements
HTML "void" elements (like <br>, <img>, <hr>) are handled specially. They trigger an immediate closure event after their opening event, as they cannot have children.
Sources: src/Parser.ts:103-124, src/Parser.ts:520-522
Foreign Contexts (SVG and MathML)
The parser tracks whether it is inside a foreign namespace, which changes tag name normalization and self-closing tag behavior.
- Detection: Entering
<svg>or<math>pushes a newForeignContext. - Integration Points: Elements like
foreignObjector MathMLmiact as integration points where HTML rules may resume. - Case Adjustment: SVG tag names are adjusted to their proper camelCase form (e.g.,
clippathbecomesclipPath) even iflowerCaseTagsis enabled.
Sources: src/Parser.ts:172-211, src/Parser.ts:451-466
Summary of Tag and Attribute Events
The following events are available in the Handler interface for consuming tag and attribute data:
| Event | Parameters | Description |
|---|---|---|
onopentagname | name: string | Emitted as soon as the tag name is identified. |
onattribute | name: string, value: string, quote?: string | Emitted for each attribute found in a tag. |
onopentag | name: string, attribs: Object, isImplied: boolean | Emitted when the entire opening tag is processed. |
onclosetag | name: string, isImplied: boolean | Emitted when a tag is closed (explicitly or implicitly). |
onselfclosingtag | endIndex: number | Internal event when /> is encountered; triggers onclosetag if recognized. |
Sources: src/Parser.ts:279-301, src/Tokenizer.ts:145-160, README.md:65-75
Conclusion
The htmlparser2 event system for tags and attributes provides a robust foundation for building DOM trees or streaming processors. By managing a stateful stack and adhering to HTML-specific nesting rules, the parser ensures that developers receive a coherent stream of structural events even when processing malformed or complex HTML documents. The separation between the Tokenizer's character-level states and the Parser's element-level logic allows for high efficiency without sacrificing the complexity required for full HTML compatibility.