# HG changeset patch # User Paul Boddie # Date 1222463184 -7200 # Node ID f33bc3431214f614d10ba134c8ae92f79f1173c0 # Parent 0a3f4b5a51d73649e9c4edf0d7302826b12f429f Changed text node handling around insertBefore and appendChild, since the underlying libxml2mod functions previously employed would merge text nodes and silently free redundant nodes, causing potential crash situations. Added a test of text node handling. Updated release information. diff -r 0a3f4b5a51d7 -r f33bc3431214 README.txt --- a/README.txt Sun Sep 14 22:55:59 2008 +0200 +++ b/README.txt Fri Sep 26 23:06:24 2008 +0200 @@ -70,6 +70,8 @@ New in libxml2dom 0.5 (Changes since libxml2dom 0.4.7) ------------------------------------------------------ + * Fixed text node handling to work around the libxml2 tendency to merge text + nodes in its own functions. * Changed some XML-RPC node properties in order to retain underlying DOM properties such as data. * Added convenience methods to the XML-RPC implementation, with combined diff -r 0a3f4b5a51d7 -r f33bc3431214 libxml2dom/__init__.py --- a/libxml2dom/__init__.py Sun Sep 14 22:55:59 2008 +0200 +++ b/libxml2dom/__init__.py Fri Sep 26 23:06:24 2008 +0200 @@ -19,7 +19,7 @@ with this program. If not, see . """ -__version__ = "0.4.8" +__version__ = "0.5" from libxml2dom.macrolib import * from libxml2dom.macrolib import \ @@ -396,34 +396,46 @@ raise xml.dom.WrongDocumentErr() if oldNode.parentNode != self: raise xml.dom.NotFoundErr() - if hasattr(tmp, "as_native_node"): - return self.impl.get_node(Node_insertBefore(self._node, tmp.as_native_node(), oldNode.as_native_node()), self) - else: - return self.impl.get_node(Node_insertBefore(self._node, tmp, oldNode.as_native_node()), self) + + # Nodes must be from this implementation before insertion. + + if not hasattr(tmp, "as_native_node"): + raise xml.dom.WrongDocumentErr() + + return self.impl.get_node(Node_insertBefore(self._node, tmp.as_native_node(), oldNode.as_native_node()), self) def replaceChild(self, tmp, oldNode): if tmp.ownerDocument != self.ownerDocument: raise xml.dom.WrongDocumentErr() if oldNode.parentNode != self: raise xml.dom.NotFoundErr() - if hasattr(tmp, "as_native_node"): - return self.impl.get_node(Node_replaceChild(self._node, tmp.as_native_node(), oldNode.as_native_node()), self) - else: - return self.impl.get_node(Node_replaceChild(self._node, tmp, oldNode.as_native_node()), self) + + # Nodes must be from this implementation before insertion. + + if not hasattr(tmp, "as_native_node"): + raise xml.dom.WrongDocumentErr() + + return self.impl.get_node(Node_replaceChild(self._node, tmp.as_native_node(), oldNode.as_native_node()), self) def appendChild(self, tmp): if tmp.ownerDocument != self.ownerDocument: raise xml.dom.WrongDocumentErr() - if hasattr(tmp, "as_native_node"): - return self.impl.get_node(Node_appendChild(self._node, tmp.as_native_node()), self) - else: - return self.impl.get_node(Node_appendChild(self._node, tmp), self) + + # Nodes must be from this implementation before insertion. + + if not hasattr(tmp, "as_native_node"): + raise xml.dom.WrongDocumentErr() + + return self.impl.get_node(Node_appendChild(self._node, tmp.as_native_node()), self) def removeChild(self, tmp): - if hasattr(tmp, "as_native_node"): - Node_removeChild(self._node, tmp.as_native_node()) - else: - Node_removeChild(self._node, tmp) + + # Nodes must be from this implementation in order to be removed. + + if not hasattr(tmp, "as_native_node"): + raise xml.dom.WrongDocumentErr() + + Node_removeChild(self._node, tmp.as_native_node()) return tmp def getElementById(self, identifier): diff -r 0a3f4b5a51d7 -r f33bc3431214 libxml2dom/macrolib/__init__.py --- a/libxml2dom/macrolib/__init__.py Sun Sep 14 22:55:59 2008 +0200 +++ b/libxml2dom/macrolib/__init__.py Fri Sep 26 23:06:24 2008 +0200 @@ -19,7 +19,7 @@ with this program. If not, see . """ -__version__ = "0.4.8" +__version__ = "0.5" # Expose all functions here. diff -r 0a3f4b5a51d7 -r f33bc3431214 libxml2dom/macrolib/macrolib.py --- a/libxml2dom/macrolib/macrolib.py Sun Sep 14 22:55:59 2008 +0200 +++ b/libxml2dom/macrolib/macrolib.py Fri Sep 26 23:06:24 2008 +0200 @@ -429,13 +429,31 @@ return libxml2mod.xmlNewCDataBlock(Node_ownerDocument(node), value, len(value)) def Node_insertBefore(node, tmp, oldNode): - return libxml2mod.xmlAddPrevSibling(oldNode, tmp) + + # Work around libxml2 tendency to merge text nodes and free nodes silently. + + if libxml2mod.type(tmp) == "text": + placeholder = libxml2mod.xmlNewNode("tmp") + placeholder = libxml2mod.xmlAddPrevSibling(oldNode, placeholder) + libxml2mod.xmlReplaceNode(placeholder, tmp) + return tmp + else: + return libxml2mod.xmlAddPrevSibling(oldNode, tmp) def Node_replaceChild(node, tmp, oldNode): return libxml2mod.xmlReplaceNode(oldNode, tmp) def Node_appendChild(node, tmp): - return libxml2mod.xmlAddChild(node, tmp) + + # Work around libxml2 tendency to merge text nodes and free nodes silently. + + if libxml2mod.type(tmp) == "text": + placeholder = libxml2mod.xmlNewNode("tmp") + placeholder = libxml2mod.xmlAddChild(node, placeholder) + libxml2mod.xmlReplaceNode(placeholder, tmp) + return tmp + else: + return libxml2mod.xmlAddChild(node, tmp) def Node_removeChild(node, child): libxml2mod.xmlUnlinkNode(child) diff -r 0a3f4b5a51d7 -r f33bc3431214 packages/debian-etch/python-libxml2dom/debian/changelog --- a/packages/debian-etch/python-libxml2dom/debian/changelog Sun Sep 14 22:55:59 2008 +0200 +++ b/packages/debian-etch/python-libxml2dom/debian/changelog Fri Sep 26 23:06:24 2008 +0200 @@ -1,5 +1,7 @@ libxml2dom (0.5-0ubuntu1) stable; urgency=low + * Fixed text node handling to work around the libxml2 + tendency to merge text nodes in its own functions. * Changed some XML-RPC node properties in order to retain underlying DOM properties such as data. * Added convenience methods to the XML-RPC implementation, diff -r 0a3f4b5a51d7 -r f33bc3431214 packages/debian-sarge/python2.3-libxml2dom/debian/changelog --- a/packages/debian-sarge/python2.3-libxml2dom/debian/changelog Sun Sep 14 22:55:59 2008 +0200 +++ b/packages/debian-sarge/python2.3-libxml2dom/debian/changelog Fri Sep 26 23:06:24 2008 +0200 @@ -1,5 +1,7 @@ libxml2dom (0.5-0ubuntu1) stable; urgency=low + * Fixed text node handling to work around the libxml2 + tendency to merge text nodes in its own functions. * Changed some XML-RPC node properties in order to retain underlying DOM properties such as data. * Added convenience methods to the XML-RPC implementation, diff -r 0a3f4b5a51d7 -r f33bc3431214 packages/ubuntu-feisty/python-libxml2dom/debian/changelog --- a/packages/ubuntu-feisty/python-libxml2dom/debian/changelog Sun Sep 14 22:55:59 2008 +0200 +++ b/packages/ubuntu-feisty/python-libxml2dom/debian/changelog Fri Sep 26 23:06:24 2008 +0200 @@ -1,5 +1,7 @@ libxml2dom (0.5-0ubuntu1) feisty; urgency=low + * Fixed text node handling to work around the libxml2 + tendency to merge text nodes in its own functions. * Changed some XML-RPC node properties in order to retain underlying DOM properties such as data. * Added convenience methods to the XML-RPC implementation, diff -r 0a3f4b5a51d7 -r f33bc3431214 packages/ubuntu-hoary/python2.4-libxml2dom/debian/changelog --- a/packages/ubuntu-hoary/python2.4-libxml2dom/debian/changelog Sun Sep 14 22:55:59 2008 +0200 +++ b/packages/ubuntu-hoary/python2.4-libxml2dom/debian/changelog Fri Sep 26 23:06:24 2008 +0200 @@ -1,5 +1,7 @@ libxml2dom (0.5-0ubuntu1) hoary; urgency=low + * Fixed text node handling to work around the libxml2 + tendency to merge text nodes in its own functions. * Changed some XML-RPC node properties in order to retain underlying DOM properties such as data. * Added convenience methods to the XML-RPC implementation, diff -r 0a3f4b5a51d7 -r f33bc3431214 tests/test_text_nodes.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test_text_nodes.py Fri Sep 26 23:06:24 2008 +0200 @@ -0,0 +1,30 @@ +#!/usr/bin/env python + +"Test text node insertion." + +import libxml2dom + +d = libxml2dom.createDocument(None, "test", None) + +t1 = d.createTextNode("Hello ") +t2 = d.createTextNode("world") +t3 = d.createTextNode("!") + +t1x = d.documentElement.appendChild(t1) +t3x = d.documentElement.appendChild(t3) + +print d.toString() +assert t2.parentNode is None +assert t1.parentNode is not None +assert t3.parentNode is not None + +t2x = d.documentElement.insertBefore(t2, t3) + +print d.toString() + +l = [n.data for n in t1.parentNode.childNodes] + +print l +assert len(l) == 3 + +# vim: tabstop=4 expandtab shiftwidth=4