Skip to content

XML v0.5 (WIP) — FlatNode, node identity, LazyNode XPath#85

Draft
mathieu17g wants to merge 7 commits into
mainfrom
v0.5-dev
Draft

XML v0.5 (WIP) — FlatNode, node identity, LazyNode XPath#85
mathieu17g wants to merge 7 commits into
mainfrom
v0.5-dev

Conversation

@mathieu17g

Copy link
Copy Markdown
Collaborator

Long-lived integration PR for XML v0.5 — mirrors the role #76 played for v0.4: every push to v0.5-dev gets the full CI matrix + the XLSX Downstream check, and this PR is the eventual merge vehicle for the release.

Landed so far:

Backlog before release: ===/hash redesign on Node (#83, #55), LazyNode XPath (#79).

mathieu17g and others added 7 commits July 5, 2026 18:43
The fourth reader alongside Node/LazyNode/Cursor: parse(xml, FlatNode)
materializes the whole document once into a contiguous store of isbits
records (parent/first_child/next_sibling index links, zero-copy byte
ranges into the retained source), so building is fast, random access is
O(1), and the GC traces a handful of arrays instead of one object per
node. Text and attribute values are entity-decoded at access (the
has_entities token flag rides the sign bit of the stored length).

The builder is the same single visibly-pushdown pass as _parse with the
same well-formedness checks at the same token points (shared check
functions; identical error messages, asserted by the parity tests).
FlatNode == / hash are positional identity — same store, same node
(the #83 semantics, debuting on the new reader). Node(flatnode)
materializes a subtree as a mutable Node; XML.write accepts FlatNode.
O(1) parent and O(depth) 1-arg depth come free from the stored links.

Assisted-by: Claude (Anthropic)
The new W3C parity testset asserts FlatNode ≡ Node (decoded trees) on
every well-formed document of the pinned conformance suite, and the
exact same accept/reject verdict on every not-well-formed one — any
divergence between the flat builder and _parse is a named failure.

It caught exactly one on first run, on 5 documents (sun/invalid/empty.xml,
oasis p15pass1/p18pass1, ibm P15/P20): an empty comment <!----> or CDATA
<![CDATA[]]> has value "" on Node but came back nothing on FlatNode,
because the record encoded absence as len == 0. Absence is now
value_offset == -1 (empty content keeps a real offset with len 0),
matching the Node parser on all three states: absent, empty, present.

Assisted-by: Claude (Anthropic)
Add FlatNode: read-only columnar full-DOM reader (#82)
benchmarks/flatnode_bench.jl measures build/walk/extract/retained/GC
against Node, Cursor and EzXML (min-of-5, XMark). Findings recorded:
FlatNode wins build 1.8x, structural walk 1.7x, retained 1.7x, and
end-to-end extraction 1.65x; pure accessor loops over an already-built
tree remain ~1.8x slower than Node's direct field reads (SubString
construction + boundary walks) — the one regime where the mutable DOM
is faster, documented rather than chased into unsafe string internals.

Assisted-by: Claude (Anthropic)
A parallel spans column in the store (SoA style — no record churn,
+8 B/node) tracks each node's exact raw source slice, set from the
opening marker token and patched at the closing one (the CLOSE_TAG
token covers only '</name'; the closing '>' — ETag allows 'S? >' — is
located with findnext). sourcetext(::FlatNode) returns the zero-copy
slice, asserted equal to LazyNode's sourcetext, and unblocks consumers
that keep raw entry slices (e.g. XLSX's shared-string table loader).

Assisted-by: Claude (Anthropic)
Needed by consumers that probe <t>-style leaves (e.g. XLSX's shared
string loader); asserted against Node in the accessor parity tests.

Assisted-by: Claude (Anthropic)
@codecov-commenter

codecov-commenter commented Jul 5, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 96.96970% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.94%. Comparing base (a3f57d8) to head (714639a).

Files with missing lines Patch % Lines
src/flatnode.jl 96.96% 8 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main      #85      +/-   ##
==========================================
+ Coverage   94.47%   94.94%   +0.46%     
==========================================
  Files          11       12       +1     
  Lines        1793     2057     +264     
==========================================
+ Hits         1694     1953     +259     
- Misses         99      104       +5     
Files with missing lines Coverage Δ
src/XML.jl 100.00% <ø> (ø)
src/flatnode.jl 96.96% <96.96%> (ø)

... and 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants