Parse the XML declaration's pseudo-attributes instead of skipping the
<?xml?> processing instruction:
- version, encoding, and standalone are surfaced on a new XMLDeclaration,
returned from parseWithDocumentType and via PureXML.xmlDeclaration(_:).
- The pseudo-attributes are validated: fixed order (version, encoding,
standalone), known names only, and standalone must be yes or no. A
malformed declaration is rejected.
- The declared version is now readable, a prerequisite for XML 1.1.
parseWithDocumentType returns a ParsedDocument struct (node,
documentType, declaration) rather than a 2-tuple; the member names are
unchanged so existing call sites are unaffected.
Closes#95
Add opt-in DTD processing behind Limits(allowDoctype:), off by default. When on,
DoctypeScanner reads the <!DOCTYPE> internal subset and honors internal
<!ENTITY name "value"> general entities, which EntityDecoder expands recursively
in text and attribute values.
Safety is mandatory and reimplemented from the Expat amplification-accounting
model (no upstream code copied):
- only entity-expanded characters count against a shared budget
(Limits.maxEntityExpansion); overflow raises amplificationLimitExceeded, which
defeats billion-laughs.
- a visiting set detects recursive entities (recursiveEntity).
- undeclared references raise undefinedEntity.
- external entities are never stored or loaded, so XXE stays closed.
The default still rejects <!DOCTYPE>. 8 DTD tests (incl. billion-laughs and the
external-entity refusal); 49 total.
Add namespace resolution following the XML Namespaces rules, reimplemented in
Swift from libxml2's SAX2 model; no upstream code copied.
- QualifiedName gains an optional resolved namespaceURI (nil for names built
directly or in no namespace), with a resolved(namespaceURI:) helper.
- NamespaceContext maintains a scope stack of xmlns bindings as elements open
and close, resolving element and attribute names against it.
- A default namespace applies to unprefixed element names but never to
attributes; the xml prefix is built in; xmlns declarations are preserved as
attributes so documents round-trip; an unbound prefix raises
ParseError.undefinedNamespacePrefix. End-tag matching stays lexical.
- Namespace-free documents are unchanged (URIs remain nil).
- 7 namespace tests; 39 total.
Add PureXML.parse(bytes:) and events(bytes:) for raw [UInt8] input. The encoding
is detected following the XML sniff order (BOM first, then the <? byte pattern,
defaulting to UTF-8) and decoded with the Swift standard library only, so the
package stays Foundation-free and portable. UTF-8 and UTF-16 (both byte orders,
with or without a BOM) are supported, the encoding set the XML spec requires.
Malformed input (odd-length UTF-16) raises ParseError.malformedEncoding.
PureXML.Parsing.InputEncoding.detect(_:) exposes the detector. The lint rule
optional_data_string_conversion is disabled because its suggested fix is a
Foundation API this package cannot use. Reimplemented from the documented XML
byte-detection algorithm; no upstream code copied.
Add PureXML.Parsing.Limits: configurable caps on nesting depth (default 256,
matching libxml2), name length, and content length, enforced during scanning in
the event reader. This protects against pathological input (deeply nested or
oversized documents) and keeps the recursive Model.Node value safe to build and
tear down (extreme depth otherwise overflows on ARC release). Threaded through
Parser.parse and the top-level parse/events API. Reimplemented from libxml2's
bounded-by-default posture; no upstream code copied.
Replace the notImplemented stub with a real parser built on a pull-based,
streaming event core that never requires the whole document in memory.
- Parsing.EventReader: pulls characters through a source closure with a bounded
lookahead buffer and emits one Parsing.Event at a time, holding only an
open-element stack. Drives chunked/streamed input.
- Parsing.Parser: builds a Model.Node tree iteratively over the event core
(explicit stack, no recursion).
- Reader: streaming character cursor (closure-backed, bounded buffer) replacing
the previous whole-string Array.
- EntityDecoder: the five predefined entities and decimal/hex char references.
- Handles elements, attributes, text, comments, CDATA, processing instructions,
and an XML declaration in the prolog. Rejects <!DOCTYPE> by default (no
DTD/XXE/entity-expansion exposure).
- Top-level API: parse(_:), parse(pulling:), events(_:), events(pulling:).
- 21 tests including event-stream and chunked-source coverage.
Root Swift package mirroring PureYAML's structure, rules, and verification
gates. Includes the XML node model (Node, Element, Attribute, QualifiedName),
a working emitter (Serializer) with escaping and pretty/compact options, and
structural validation. The parser surface is stable; parse() raises
notImplemented until the scanner lands, pinned by a test.
- dependency-free, namespaced under PureXML
- portability and style gates carried over (style, namespacing, forbidden
patterns, swiftformat, swiftlint, linux, wasm, windows CI)
- 11 tests passing