Skip to content

✨ feat(serialize): add XML/XHTML output syntax#564

Merged
gaborbernat merged 1 commit into
tox-dev:mainfrom
gaborbernat:feat/535-xml-output
Jul 7, 2026
Merged

✨ feat(serialize): add XML/XHTML output syntax#564
gaborbernat merged 1 commit into
tox-dev:mainfrom
gaborbernat:feat/535-xml-output

Conversation

@gaborbernat

Copy link
Copy Markdown
Member

turbohtml serialized HTML syntax only, so a tree bound for an XML toolchain (an XSLT or XPath 2.0 pipeline, an XMLSerializer consumer, anything that rejects HTML's unclosed tags) had to be round-tripped through a second library. This adds an XML/XHTML serialization mode, the equivalent of lxml's tostring(method="xml"), so serialize, encode, and serialize_iter can emit well-formed XML from the same parsed tree.

Html gained an xml field. With xml=True the WHATWG XML serialization rules apply: every empty element self-closes (<br/>, <div/>), a foreign SVG or MathML subtree carries the namespace declaration that makes it well-formed (xmlns on the subtree root, xmlns:xlink on any element bearing an xlink: attribute), and text and attribute values follow the XML escaping rules (&, <, > in text, plus " and the whitespace characters in attributes, with a no-break space left literal since XML predefines no &nbsp;). The HTML void-element and raw-text special casing does not apply, so a <script> body is escaped like any other text.

The serializer keeps its single tree walk and branches on the flag at the four points where the HTML and XML algorithms diverge, so the HTML fast path stays intact. 🚀 The flag composes with sort_attributes and an Indent layout; a Minify layout stays HTML, since its optional-tag and unquoted-attribute rules are HTML-parser rules.

The docs/migration/lxml.rst guide maps tostring(method="xml"|"xhtml") onto serialize(Html(xml=True)), and a serialize-xml benchmark op compares turbohtml against lxml's method="xml" head to head.

closes #535

Html gained an xml field that switches serialize/encode/serialize_iter
from HTML to XML output, the equivalent of lxml's tostring(method="xml").
Every empty element self-closes, a foreign SVG or MathML subtree carries
the namespace declaration that makes it well-formed, and text and
attribute values follow the XML escaping rules, with no HTML void-element
or raw-text special casing.

The serializer keeps its single tree walk and branches on the flag at the
four points where the HTML and XML algorithms diverge (empty-element
form, raw text, escaping, namespaces), so the HTML fast path is
untouched. The flag composes with sort_attributes and an Indent layout; a
Minify layout stays HTML, since its optional-tag and unquoted-attribute
rules are HTML-parser rules.

closes tox-dev#535
@gaborbernat gaborbernat added the enhancement New feature or request label Jul 7, 2026
@codspeed-hq

codspeed-hq Bot commented Jul 7, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 66 untouched benchmarks
🆕 1 new benchmark
⏩ 18 skipped benchmarks1

Performance Changes

Benchmark BASE HEAD Efficiency
🆕 test_feature[serialize-xml] N/A 2.9 ms N/A

Comparing gaborbernat:feat/535-xml-output (478d12f) with main (e9032d7)

Open in CodSpeed

Footnotes

  1. 18 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@gaborbernat gaborbernat merged commit 9a3f1a6 into tox-dev:main Jul 7, 2026
48 checks passed
@gaborbernat gaborbernat deleted the feat/535-xml-output branch July 10, 2026 18:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Serializer: XML/XHTML output syntax

1 participant