This page documents @lanexio/parser-grammar-xml, the XML grammar package implementing XML 1.0 5th Edition with optional DTD validation, external entity resolution, and comprehensive attribute-level DTD information.
Version:Stable
Module name:parser-grammar-xml
Package:@lanexio/parser-grammar-xml
Import path:@lanexio/parser-grammar-xml
Layer: 2 (Grammar)
Runtime: Universal
Module format: ESM
Stability: Stable
Primary use case: Parse XML documents into a flat AST with optional DTD validation.
const tree = parseXml(encoder.encode('<a xmlns:p="urn:x"><p:b/></a>'), {
mode: 'strict',
});
mode: "strict" (or the strict: true alias, ADR 0044) is the strict
conformance profile whose contract is “WF + reject external-DTD /
undefined-entity”. On top of the always-on well-formedness checks it runs:
namespace-prefix well-formedness unconditionally: an unbound element or
attribute prefix flags the node even in documents with no namespace
declarations;
internal-subset DTD validation when the document carries an internal DTD
subset (VC: Root Element Type, element content models, attribute
constraints);
the external-DTD surface: a DOCTYPE that references an external subset
(SYSTEM or PUBLIC) which no resolver read flags the DocType node as an error
node and the Document root. A resolver that read the subset keeps the
reference clean.
The parse profiles compose validate and strict:
Profile
What runs
default (lenient)
WF-only recovery; an unresolved external-DTD document parses clean
full DTD validating pass on top of the strict surface
Both validate and strict forward through the registered xmlGrammar.parse
options bag and the pack parse entry point, so
parse(bytes, { grammarOptions: { validate: true, mode: "strict" } }) behaves
identically to the direct parseXml(bytes, { validate: true, mode: "strict" })
call.
Strict mode never throws; every input, including the large and non-UTF-8
fixtures in test_files/xml, produces a tree with
metadata.language === "xml" (verified by the strict-mode corpus never-throw
sweep).
The default mode: "lenient" stays well-formedness-strict and byte-lossless but
does not run the strict profile; files that error only in strict mode are
strict-profile rejections (unbound prefixes, internal-subset DTD violations,
unresolved external-DTD references), not well-formedness defects. See the
XML conformance page for the artifact reclassification
table (xml-1.1, not-wf, errors/fail, non-UTF-8 encodings, c14n, errata, and the
remaining documented buckets) that keeps the REAL-DEFECT bucket empty.
"strict" runs the strict conformance profile (ADR 0044): namespace-prefix well-formedness unconditionally, internal-subset DTD validation, and the external-DTD surface (an unresolved external subset flags the DocType). Never throws.
validate
boolean
No
false
When true, runs the full DTD validating pass after parsing (VC Root Element Type, element content models, attribute constraints). Forwarded through xmlGrammar.parse and the pack parse entry point.
resolveExternal
ExternalResolver
No
undefined
Callback for resolving external DTD subset references. The parser does no I/O.
baseUri
string
No
""
Base URI for resolving relative SYSTEM identifiers.
namespaceCheck
boolean
No
true
When false, skip namespace prefix resolution and xmlns declaration tracking.
language
string
No
"xml"
Language stamp written to tree.metadata.language on every parse result. Future sub-dialects (such as the registered xhtml/svg aliases) may pass their own.
Language stamp on every parse result — "xml" by default, or the language option value. An empty document parses to a Document node containing a single XmlKind.Error leaf (root.hasError is true).
The resolveExternal callback allows callers to provide external DTD content without the parser performing network I/O. The parser’s no-expand security model prevents billion-laughs attacks.
Never-throw on large spans in both profiles: chunked decodeRange replaces the unbounded spread-decode sites. Strict-mode corpus sweep (6112 files) never throws.