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