# HG changeset patch # User paulb # Date 1176072719 0 # Node ID e062bab9737f16fa009ddc6a9ec9f220b8c8edf6 # Parent e0163c19269aea614585035ef02f9afee6876679 [project @ 2007-04-08 22:51:59 by paulb] Added firstChild, lastChild, a NamedNodeMapIterator class. Fixed doctype retrieval for null doctypes. Moved document checking into the Node class. Introduced a Node_equals function for comparisons. diff -r e0163c19269a -r e062bab9737f libxml2dom/__init__.py --- a/libxml2dom/__init__.py Sun Apr 08 22:50:34 2007 +0000 +++ b/libxml2dom/__init__.py Sun Apr 08 22:51:59 2007 +0000 @@ -114,6 +114,11 @@ self.node.removeAttributeNS(ns, localName) return old + # Iterator emulation. + + def __iter__(self): + return NamedNodeMapIterator(self) + # Dictionary emulation methods. def __getitem__(self, name): @@ -149,6 +154,22 @@ length = property(_length) +class NamedNodeMapIterator(object): + + "An iterator over a NamedNodeMap." + + def __init__(self, nodemap): + self.nodemap = nodemap + self.items = self.nodemap.items() + + def next(self): + if self.items: + current = self.items[0][1] + self.items = self.items[1:] + return current + else: + raise StopIteration + class NodeList(list): "A wrapper around node lists." @@ -197,6 +218,12 @@ return NodeList([self.impl.get_node(_node, self) for _node in Node_childNodes(self._node)]) + def _firstChild(self): + return (self.childNodes or [None])[0] + + def _lastChild(self): + return (self.childNodes or [None])[-1] + def _attributes(self): return NamedNodeMap(self, self.impl) @@ -236,7 +263,11 @@ return self.impl.get_node_or_none(Node_nextSibling(self._node), self) def _doctype(self): - return self.impl.get_node(Node_doctype(self._node), self) + _doctype = Node_doctype(self._node) + if _doctype is not None: + return self.impl.get_node(_doctype, self) + else: + return None def _publicId(self): # NOTE: To be fixed when the libxml2mod API has been figured out. @@ -341,18 +372,28 @@ return self.importNode(self, deep) def insertBefore(self, tmp, oldNode): + if tmp.ownerDocument != self.ownerDocument: + raise xml.dom.DOMException(xml.dom.WRONG_DOCUMENT_ERR) + if oldNode.parentNode != self: + raise xml.dom.DOMException(xml.dom.NOT_FOUND_ERR) 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) def replaceChild(self, tmp, oldNode): + if tmp.ownerDocument != self.ownerDocument: + raise xml.dom.DOMException(xml.dom.WRONG_DOCUMENT_ERR) + if oldNode.parentNode != self: + raise xml.dom.DOMException(xml.dom.NOT_FOUND_ERR) 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) def appendChild(self, tmp): + if tmp.ownerDocument != self.ownerDocument: + raise xml.dom.DOMException(xml.dom.WRONG_DOCUMENT_ERR) if hasattr(tmp, "as_native_node"): return self.impl.get_node(Node_appendChild(self._node, tmp.as_native_node()), self) else: @@ -363,6 +404,7 @@ Node_removeChild(self._node, tmp.as_native_node()) else: Node_removeChild(self._node, tmp) + return tmp def getElementById(self, identifier): nodes = self.xpath(".//*[@xml:id='" + identifier.replace("'", "'") + "']", @@ -398,6 +440,8 @@ self.replaceChild(self.ownerDocument.createTextNode("".join(texts)), text_nodes[-1]) childNodes = property(_childNodes) + firstChild = property(_firstChild) + lastChild = property(_lastChild) value = data = nodeValue = property(_nodeValue, _setNodeValue) textContent = property(_textContent) name = nodeName = property(_nodeName) @@ -426,7 +470,7 @@ return hash(self.localName) def __eq__(self, other): - return isinstance(other, Node) and libxml2mod.xmlXPathCmpNodes(self._node, other._node) == 0 + return isinstance(other, Node) and Node_equals(self._node, other._node) def __ne__(self, other): return not (self == other)