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 pass 19 20 def getNamedItemNS(self, ns, localName): 21 pass 22 23 def setNamedItem(self, node): 24 pass 25 26 def setNamedItemNS(self, node): 27 pass 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 Node(object): 76 77 _nodeTypes = { 78 "attribute" : xml.dom.Node.ATTRIBUTE_NODE, 79 "comment" : xml.dom.Node.COMMENT_NODE, 80 "document_xml" : xml.dom.Node.DOCUMENT_NODE, 81 "doctype" : xml.dom.Node.DOCUMENT_TYPE_NODE, 82 "element" : xml.dom.Node.ELEMENT_NODE, 83 "entity" : xml.dom.Node.ENTITY_NODE, 84 "entity_ref" : xml.dom.Node.ENTITY_REFERENCE_NODE, 85 "notation" : xml.dom.Node.NOTATION_NODE, 86 "pi" : xml.dom.Node.PROCESSING_INSTRUCTION_NODE, 87 "text" : xml.dom.Node.TEXT_NODE 88 } 89 90 def __init__(self, node, ownerElement=None): 91 self._node = node 92 self.ownerElement = ownerElement 93 94 def _ownerDocument(self): 95 return self._node.doc 96 97 def _nodeType(self): 98 return self._nodeTypes[self._node.type] 99 100 def _childNodes(self): 101 102 # NOTE: Consider a generator instead. 103 104 child_nodes = [] 105 child_node = self._node.children 106 while child_node is not None: 107 child_nodes.append( 108 self.__class__(child_node)) 109 child_node = child_node.next 110 return child_nodes 111 112 def _attributes(self): 113 return NamedNodeMap(self) 114 115 def _getNs(self): 116 117 "Internal namespace information retrieval." 118 119 try: 120 return self._node.ns() 121 except libxml2.treeError: 122 return None 123 124 def _namespaceURI(self): 125 ns = self._getNs() 126 if ns is not None: 127 return ns.content 128 else: 129 return None 130 131 def _nodeValue(self): 132 return self._node.content 133 134 def _prefix(self): 135 ns = self._getNs() 136 if ns is not None: 137 return ns.name 138 else: 139 return None 140 141 def _nodeName(self): 142 prefix = self._prefix() 143 if prefix is not None: 144 return prefix + ":" + self._localName() 145 else: 146 return self._localName() 147 148 def _tagName(self): 149 if self._node.type == "element": 150 return self._nodeName() 151 else: 152 return None 153 154 def _localName(self): 155 return self._node.name 156 157 def _parentNode(self): 158 return self._node.parent 159 160 def getAttributeNS(self, ns, localName): 161 return self._node.nsProp(localName, ns) 162 163 def getAttribute(self, name): 164 return self._node.prop(localName) 165 166 def getAttributeNodeNS(self, ns, localName): 167 return self.attributes[(ns, localName)] 168 169 def getAttributeNode(self, localName): 170 # NOTE: Needs verifying. 171 return self.attributes[(None, localName)] 172 173 def setAttributeNS(self, ns, name, value): 174 prefix, localName = _get_prefix_and_localName(name) 175 if localName: 176 self._node.setNsProp(self._node.newNs(ns, prefix), localName, value) 177 178 def setAttribute(self, name, value): 179 self._node.setProp(name, value) 180 181 def setAttributeNodeNS(self, ns, name, node): 182 # NOTE: Not actually putting the node on the element. 183 self.setAttributeNS(ns, name, node.nodeValue) 184 185 def setAttributeNode(self, name, node): 186 # NOTE: Not actually putting the node on the element. 187 self.setAttribute(name, node.nodeValue) 188 189 def createElementNS(self, ns, name): 190 prefix, localName = _get_prefix_and_localName(name) 191 return TemporaryNode(ns, name, xml.dom.Node.ELEMENT_NODE) 192 193 def createElement(self, name): 194 return TemporaryNode(None, name, xml.dom.Node.ELEMENT_NODE) 195 196 def createAttributeNS(self, ns, name): 197 prefix, localName = _get_prefix_and_localName(name) 198 return TemporaryNode(ns, name, xml.dom.Node.ATTRIBUTE_NODE) 199 200 def createAttribute(self, name): 201 return TemporaryNode(ns, name, xml.dom.Node.ATTRIBUTE_NODE) 202 203 def _add_node(self, tmp): 204 if tmp.ns is not None: 205 if tmp.nodeType == xml.dom.Node.ELEMENT_NODE: 206 _child = self._node.newChild(None, tmp.localName, None) 207 elif tmp.nodeType == xml.dom.Node.ATTRIBUTE_NODE: 208 _child = self._node.newNsProp(None, tmp.localName, None) 209 else: 210 _child = None 211 212 if _child is not None: 213 _ns = _child.newNs(tmp.ns, tmp.prefix) 214 _child.setNs(_ns) 215 else: 216 if tmp.nodeType == xml.dom.Node.ELEMENT_NODE: 217 _child = self._node.newChild(None, tmp.name, None) 218 elif tmp.nodeType == xml.dom.Node.ATTRIBUTE_NODE: 219 _child = self._node.newProp(None, tmp.name, None) 220 else: 221 _child = None 222 223 return _child 224 225 def insertBefore(self, tmp, oldNode): 226 _child = self._add_node(tmp) 227 _child.unlinkNode() 228 return Node(oldNode._node.addPrevSibling(_child)) 229 230 def replaceChild(self, tmp, oldNode): 231 _child = self._add_node(tmp) 232 _child.unlinkNode() 233 return Node(oldNode._node.replaceNode(_child)) 234 235 def appendChild(self, tmp): 236 return Node(self._add_node(tmp)) 237 238 #doctype = property(_doctype) 239 #ownerElement = property(_ownerElement) 240 ownerDocument = property(_ownerDocument) 241 childNodes = property(_childNodes) 242 value = data = nodeValue = property(_nodeValue) 243 name = nodeName = property(_nodeName) 244 tagName = property(_tagName) 245 namespaceURI = property(_namespaceURI) 246 prefix = property(_prefix) 247 localName = property(_localName) 248 parentNode = property(_parentNode) 249 nodeType = property(_nodeType) 250 attributes = property(_attributes) 251 252 def isSameNode(self, other): 253 return self._node.nodePath() == other._node.nodePath() 254 255 def __eq__(self, other): 256 return self._node.nodePath() == other._node.nodePath() 257 258 # vim: tabstop=4 expandtab shiftwidth=4