Index: Lib/xml/dom/minidom.py =================================================================== --- Lib/xml/dom/minidom.py (revision 61002) +++ Lib/xml/dom/minidom.py (working copy) @@ -20,6 +20,8 @@ from xml.dom.minicompat import * from xml.dom.xmlbuilder import DOMImplementationLS, DocumentLS +import itertools + # This is used by the ID-cache invalidation checks; the list isn't # actually complete, since the nodes being checked will never be the # DOCUMENT_NODE or DOCUMENT_FRAGMENT_NODE. (The node being checked is @@ -174,37 +176,32 @@ return oldChild def normalize(self): + # Pass 1: Discard empty text nodes, collapse adjacent text nodes. L = [] for child in self.childNodes: if child.nodeType == Node.TEXT_NODE: data = child.data - if data and L and L[-1].nodeType == child.nodeType: - # collapse text node - node = L[-1] - node.data = node.data + child.data - node.nextSibling = child.nextSibling + if not data: + # Discard empty text node. child.unlink() - elif data: - if L: - L[-1].nextSibling = child - child.previousSibling = L[-1] - else: - child.previousSibling = None - L.append(child) - else: - # empty text node; discard + elif L and L[-1].nodeType == Node.TEXT_NODE: + # Collapse adjacent text nodes. + L[-1].data += data child.unlink() - else: - if L: - L[-1].nextSibling = child - child.previousSibling = L[-1] else: - child.previousSibling = None + L.append(child) + else: L.append(child) if child.nodeType == Node.ELEMENT_NODE: child.normalize() - if L: - L[-1].nextSibling = None + + # Pass 2: Recreate the previous/next links. + previous_L = itertools.chain([None], L) + next_L = itertools.chain(itertools.islice(L, 1, None), [None]) + for prev, child, next in itertools.izip(previous_L, L, next_L): + child.previousSibling = prev + child.nextSibling = next + self.childNodes[:] = L def cloneNode(self, deep):