Skip to content

Serialize the Source view as Exclusive XML Canonicalization#20

Merged
namedgraph merged 1 commit into
masterfrom
feature/canonical-xml-c14n
Jul 14, 2026
Merged

Serialize the Source view as Exclusive XML Canonicalization#20
namedgraph merged 1 commit into
masterfrom
feature/canonical-xml-c14n

Conversation

@namedgraph

Copy link
Copy Markdown
Member

Problem

The Source view serialized the canonical tree with serialize(…, indent: true()), which is not a canonical form at all:

  • SaxonJS's indenter inserts line breaks and spaces between the element children of mixed content — whitespace that renders, e.g. around a figcaption's <br/>s:
    <figcaption>A single fact, split into its three<br/>
       <br/> parts.</figcaption>
  • Empty elements stayed self-closed (<br/>), attribute order was arbitrary, namespace declarations unsorted — none of the c14n rules applied.

Fix

Port LinkedDataHub's ldh:canonicalize-xml pattern:

  • Vendor LDH's xml-c14n-sync.js bundle (W3C Exclusive XML Canonicalization, xml-exc-c14n#WithComments — the rdf:XMLLiteral value space, i.e. the form this content is headed for in the LDH v6 format) into lib/, loaded alongside SaxonJS3.js by index.html and the test fixtures.
  • New local:canonicalize-xml in edit.xsl: serialize()parse-xml() bridges the XDM temporary tree to the browser DOM the lib walks, then canonicaliseSync produces the canonical string. The view-source handler now emits that instead of the indented serialization.

Output is now e.g. …its three<br></br><br></br> parts. — start/end tag pairs for empty elements, sorted attributes (<img alt="…" src="…">), sorted namespace declarations, no serializer-injected whitespace; only the document's own whitespace survives.

Note: exclusive c14n (not c14n 1.1) is deliberate — it's what rdf:XMLLiteral specifies and what LDH uses for XMLLiteral persistence; for standalone fragments with no inherited namespace context the two coincide.

Embedding contract

Host pages now include lib/xml-c14n-sync.js next to SaxonJS3.js (README + CLAUDE.md updated).

Testing

  • All 15 Playwright suites pass (view-source assertions are whitespace-tolerant and unaffected by attribute sorting).
  • Headless extractor/canonical/lint suites pass.
  • Browser probe confirms the c14n form end-to-end on the fixture page.

🤖 Generated with Claude Code

serialize(indent:true()) was no canonical form at all: SaxonJS indents
between the element children of mixed content (injecting whitespace that
renders, e.g. around a figcaption's <br/>s), empty elements stayed
self-closed and attribute order was arbitrary. Port LinkedDataHub's
ldh:canonicalize-xml instead: vendor its xml-c14n-sync.js bundle
(W3C xml-exc-c14n#WithComments, the rdf:XMLLiteral value space) and run
the canonical tree through it — serialize() → parse-xml() bridges the
XDM temporary tree to the browser DOM the lib walks. Host pages now
include the lib alongside SaxonJS3.js.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@namedgraph namedgraph merged commit 0e2b40e into master Jul 14, 2026
2 checks passed
@namedgraph namedgraph deleted the feature/canonical-xml-c14n branch July 14, 2026 22:41
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.

1 participant