GeezerVison is showing github.com — gh-160525: Fix quadratic text concatenation in xml.dom.expatbuilder by gpshead · Pull Request #160526 · python/cpython
Conversation
gpshead
commented
Oct 23, 2026
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
xml.dom.expatbuilder now collects the pieces of a run of character data in a list on the builder and joins them once, instead of copying the Text node's data on every Expat callback. The join happens at the top of every handler that adds a sibling or closes the element (start/end element in both ExpatBuilder and Namespaces, comment, PI, and the CDATA data handler), which is also before a DOMBuilderFilter or the whitespace stripping can look at the tree. The flush for CDATA is in the data handler and not in the start handler so that an empty section still does not end the run. The second commit keeps this correct for subclasses that replace those handlers without calling the base implementations: the fast path only appends while the pending Text node is still the last child of the current node, and any pending pieces are joined when parsing ends. New handlers should still call _flush_text() first, so that the Text node's data is complete whenever other code can look at it.
Parsing through xml.dom.xmlbuilder.DOMBuilder with a DOMBuilderFilter that rejects nodes is still quadratic. That comes mostly from Node.removeChild() scanning childNodes from the front, and is left for a separate issue.
Fixes #160525
ANT-2026-ZRQNVCB1 ANT-2026-QXYQ68DQ
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
…lder
Collect the pieces of a run of character data in a list and join them
once, instead of copying the Text node's data on every Expat callback.
ANT-2026-ZRQNVCB1 ANT-2026-QXYQ68DQ
…rridden
A subclass of ExpatBuilder can replace the element, comment or
processing instruction handlers without calling the base
implementations, which are what end the pending run of character data.
Check that the Text node being extended is still the last child of the
current node before adding to it, and join any pending pieces when
parsing ends, so that such subclasses keep building the same tree.
Uh oh!
There was an error while loading. Please reload this page.
Milestone
No milestone
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.