1 #!/usr/bin/env python 2 3 """ 4 DOM wrapper around libxml2. 5 """ 6 7 import xml.dom 8 import libxml2 9 10 # NOTE: Consider a generator instead. 11 12 class NamedNodeMap(object): 13 14 def __init__(self, node): 15 self.node = node 16 17 def getNamedItem(self, name): 18 return self.node.getAttributeNode(name) 19 20 def getNamedItemNS(self, ns, localName): 21 return self.node.getAttributeNodeNS(ns, localName) 22 23 def setNamedItem(self, node): 24 self.node.setAttributeNode(node.name, node) 25 26 def setNamedItemNS(self, node): 27 self.node.setAttributeNodeNS(node.namespaceURI, node.localName, node) 28 29 def __getitem__(self, name): 30 return self.getNamedItem(name) 31 32 def __setitem__(self, name, node): 33 if name == node.nodeName: 34 self.setNamedItem(node) 35 else: 36 raise KeyError, name 37 38 def __delitem__(self, name): 39 # NOTE: To be implemented. 40 pass 41 42 def values(self): 43 attributes = [] 44 _attribute = self.node._node.properties 45 while _attribute is not None: 46 attributes.append(Node(_attribute, ownerElement=self.node)) 47 _attribute = _attribute.next 48 return attributes 49 50 def keys(self): 51 return [(attr.namespaceURI, attr.localName) for attr in self.values()] 52 53 def items(self): 54 return [((attr.namespaceURI, attr.localName), attr) for attr in self.values()] 55 56 def __repr__(self): 57 return str(self) 58 59 def __str__(self): 60 return "{%s}" % ",\n".join(["%s : %s" % (repr(key), repr(value)) for key, value in self.items()]) 61 62 def _get_prefix_and_localName(name): 63 t = name.split(":") 64 if len(t) == 1: 65 return None, name 66 elif len(t) == 2: 67 return t 68 else: 69 # NOTE: Should raise an exception. 70 return None, None 71 72 class TemporaryNode(object): 73 def __init__(self, ns, name, nodeType): 74 self.ns = ns 75 self.name = name 76 self.nodeType = nodeType 77 self.prefix, self.localName = _get_prefix_and_localName(self.name) 78 79 class TemporaryText(object): 80 def __init__(self, _text): 81 self.ns = self.name = self.prefix = self.localName = None 82 self.nodeType = xml.dom.Node.TEXT_NODE 83 self._text = _text 84 85 class Node(object): 86 87 _nodeTypes = { 88 "attribute" : xml.dom.Node.ATTRIBUTE_NODE, 89 "comment" : xml.dom.Node.COMMENT_NODE, 90 "document_xml" : xml.dom.Node.DOCUMENT_NODE, 91 "doctype" : xml.dom.Node.DOCUMENT_TYPE_NODE, 92 "element" : xml.dom.Node.ELEMENT_NODE, 93 "entity" : xml.dom.Node.ENTITY_NODE, 94 "entity_ref" : xml.dom.Node.ENTITY_REFERENCE_NODE, 95 "notation" : xml.dom.Node.NOTATION_NODE, 96 "pi" : xml.dom.Node.PROCESSING_INSTRUCTION_NODE, 97 "text" : xml.dom.Node.TEXT_NODE 98 } 99 100 def __init__(self, node, ownerElement=None): 101 self._node = node 102 self.ownerElement = ownerElement 103 104 def _ownerDocument(self): 105 return self._node.doc 106 107 def _nodeType(self): 108 return self._nodeTypes[self._node.type] 109 110 def _childNodes(self): 111 112 # NOTE: Consider a generator instead. 113 114 child_nodes = [] 115 _node = self._node.children 116 while _node is not None: 117 child_nodes.append(Node(_node)) 118 _node = _node.next 119 return child_nodes 120 121 def _attributes(self): 122 return NamedNodeMap(self) 123 124 def _getNs(self): 125 126 "Internal namespace information retrieval." 127 128 try: 129 return self._node.ns() 130 except libxml2.treeError: 131 return None 132 133 def _namespaceURI(self): 134 ns = self._getNs() 135 if ns is not None: 136 return ns.content 137 else: 138 return None 139 140 def _nodeValue(self): 141 return self._node.content 142 143 def _prefix(self): 144 ns = self._getNs() 145 if ns is not None: 146 return ns.name 147 else: 148 return None 149 150 def _nodeName(self): 151 prefix = self._prefix() 152 if prefix is not None: 153 return prefix + ":" + self._localName() 154 else: 155 return self._localName() 156 157 def _tagName(self): 158 if self._node.type == "element": 159 return self._nodeName() 160 else: 161 return None 162 163 def _localName(self): 164 return self._node.name 165 166 def _parentNode(self): 167 if self.nodeType == xml.dom.Node.DOCUMENT_NODE: 168 return None 169 else: 170 return Node(self._node.parent) 171 172 def getAttributeNS(self, ns, localName): 173 return self._node.nsProp(localName, ns) 174 175 def getAttribute(self, name): 176 return self._node.prop(localName) 177 178 def getAttributeNodeNS(self, ns, localName): 179 return self.attributes[(ns, localName)] 180 181 def getAttributeNode(self, localName): 182 # NOTE: Needs verifying. 183 return self.attributes[(None, localName)] 184 185 def setAttributeNS(self, ns, name, value): 186 prefix, localName = _get_prefix_and_localName(name) 187 if localName: 188 self._node.setNsProp(self._node.newNs(ns, prefix), localName, value) 189 190 def setAttribute(self, name, value): 191 self._node.setProp(name, value) 192 193 def setAttributeNodeNS(self, ns, name, node): 194 # NOTE: Not actually putting the node on the element. 195 self.setAttributeNS(ns, name, node.nodeValue) 196 197 def setAttributeNode(self, name, node): 198 # NOTE: Not actually putting the node on the element. 199 self.setAttribute(name, node.nodeValue) 200 201 def createElementNS(self, ns, name): 202 prefix, localName = _get_prefix_and_localName(name) 203 return TemporaryNode(ns, name, xml.dom.Node.ELEMENT_NODE) 204 205 def createElement(self, name): 206 return TemporaryNode(None, name, xml.dom.Node.ELEMENT_NODE) 207 208 def createAttributeNS(self, ns, name): 209 prefix, localName = _get_prefix_and_localName(name) 210 return TemporaryNode(ns, name, xml.dom.Node.ATTRIBUTE_NODE) 211 212 def createAttribute(self, name): 213 return TemporaryNode(ns, name, xml.dom.Node.ATTRIBUTE_NODE) 214 215 def createTextNode(self, value): 216 return TemporaryText(self._node.doc.newDocText(value)) 217 218 def _add_node(self, tmp): 219 if tmp.ns is not None: 220 if tmp.nodeType == xml.dom.Node.ELEMENT_NODE: 221 _child = self._node.newChild(None, tmp.localName, None) 222 elif tmp.nodeType == xml.dom.Node.ATTRIBUTE_NODE: 223 _child = self._node.newNsProp(None, tmp.localName, None) 224 else: 225 _child = None 226 227 if _child is not None: 228 _ns = _child.newNs(tmp.ns, tmp.prefix) 229 _child.setNs(_ns) 230 else: 231 if tmp.nodeType == xml.dom.Node.ELEMENT_NODE: 232 _child = self._node.newChild(None, tmp.name, None) 233 elif tmp.nodeType == xml.dom.Node.ATTRIBUTE_NODE: 234 _child = self._node.newProp(None, tmp.name, None) 235 else: 236 _child = None 237 238 return _child 239 240 def insertBefore(self, tmp, oldNode): 241 if tmp.nodeType == xml.dom.Node.TEXT_NODE: 242 _child = tmp._text 243 else: 244 _child = self._add_node(tmp) 245 _child.unlinkNode() 246 return Node(oldNode._node.addPrevSibling(_child)) 247 248 def replaceChild(self, tmp, oldNode): 249 if tmp.nodeType == xml.dom.Node.TEXT_NODE: 250 _child = tmp._text 251 else: 252 _child = self._add_node(tmp) 253 _child.unlinkNode() 254 return Node(oldNode._node.replaceNode(_child)) 255 256 def appendChild(self, tmp): 257 if tmp.nodeType == xml.dom.Node.TEXT_NODE: 258 _child = self._node.addChild(tmp._text) 259 else: 260 _child = self._add_node(tmp) 261 return Node(_child) 262 263 #doctype = property(_doctype) 264 #ownerElement defined in __init__ 265 ownerDocument = property(_ownerDocument) 266 childNodes = property(_childNodes) 267 value = data = nodeValue = property(_nodeValue) 268 name = nodeName = property(_nodeName) 269 tagName = property(_tagName) 270 namespaceURI = property(_namespaceURI) 271 prefix = property(_prefix) 272 localName = property(_localName) 273 parentNode = property(_parentNode) 274 nodeType = property(_nodeType) 275 attributes = property(_attributes) 276 277 def isSameNode(self, other): 278 return self._node.nodePath() == other._node.nodePath() 279 280 def __eq__(self, other): 281 return self._node.nodePath() == other._node.nodePath() 282 283 # vim: tabstop=4 expandtab shiftwidth=4