1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/libxml2dom/__init__.py Sat Jan 17 22:08:50 2004 +0000
1.3 @@ -0,0 +1,396 @@
1.4 +#!/usr/bin/env python
1.5 +
1.6 +"""
1.7 +DOM wrapper around libxml2.
1.8 +"""
1.9 +
1.10 +import xml.dom
1.11 +import libxml2
1.12 +import sys
1.13 +
1.14 +# NOTE: libxml2 seems to use UTF-8 throughout.
1.15 +
1.16 +def from_unicode(s):
1.17 + if type(s) == type(u""):
1.18 + return s.encode("utf-8")
1.19 + else:
1.20 + return s
1.21 +
1.22 +def to_unicode(s):
1.23 + if type(s) == type(""):
1.24 + return unicode(s, encoding="utf-8")
1.25 + else:
1.26 + return s
1.27 +
1.28 +# NOTE: Consider a generator instead.
1.29 +
1.30 +class NamedNodeMap(object):
1.31 +
1.32 + def __init__(self, node):
1.33 + self.node = node
1.34 +
1.35 + def getNamedItem(self, name):
1.36 + return self.node.getAttributeNode(name)
1.37 +
1.38 + def getNamedItemNS(self, ns, localName):
1.39 + return self.node.getAttributeNodeNS(ns, localName)
1.40 +
1.41 + def setNamedItem(self, node):
1.42 + self.node.setAttributeNode(node.name, node)
1.43 +
1.44 + def setNamedItemNS(self, node):
1.45 + self.node.setAttributeNodeNS(node.namespaceURI, node.localName, node)
1.46 +
1.47 + def __getitem__(self, name):
1.48 + return self.getNamedItem(name)
1.49 +
1.50 + def __setitem__(self, name, node):
1.51 + if name == node.nodeName:
1.52 + self.setNamedItem(node)
1.53 + else:
1.54 + raise KeyError, name
1.55 +
1.56 + def __delitem__(self, name):
1.57 + # NOTE: To be implemented.
1.58 + pass
1.59 +
1.60 + def values(self):
1.61 + attributes = []
1.62 + _attribute = self.node.as_native_node().properties
1.63 + while _attribute is not None:
1.64 + attributes.append(Node(_attribute, ownerElement=self.node))
1.65 + _attribute = _attribute.next
1.66 + return attributes
1.67 +
1.68 + def keys(self):
1.69 + return [(attr.namespaceURI, attr.localName) for attr in self.values()]
1.70 +
1.71 + def items(self):
1.72 + return [((attr.namespaceURI, attr.localName), attr) for attr in self.values()]
1.73 +
1.74 + def __repr__(self):
1.75 + return str(self)
1.76 +
1.77 + def __str__(self):
1.78 + return "{%s}" % ",\n".join(["%s : %s" % (repr(key), repr(value)) for key, value in self.items()])
1.79 +
1.80 +def _get_prefix_and_localName(name):
1.81 + t = name.split(":")
1.82 + if len(t) == 1:
1.83 + return None, name
1.84 + elif len(t) == 2:
1.85 + return t
1.86 + else:
1.87 + # NOTE: Should raise an exception.
1.88 + return None, None
1.89 +
1.90 +class TemporaryNode(object):
1.91 + def __init__(self, ns, name, nodeType):
1.92 + self.ns = ns
1.93 + self.name = name
1.94 + self.nodeType = nodeType
1.95 + self.prefix, self.localName = _get_prefix_and_localName(self.name)
1.96 +
1.97 +class Node(object):
1.98 +
1.99 + _nodeTypes = {
1.100 + "attribute" : xml.dom.Node.ATTRIBUTE_NODE,
1.101 + "comment" : xml.dom.Node.COMMENT_NODE,
1.102 + "document_xml" : xml.dom.Node.DOCUMENT_NODE,
1.103 + "doctype" : xml.dom.Node.DOCUMENT_TYPE_NODE,
1.104 + "dtd" : xml.dom.Node.DOCUMENT_TYPE_NODE, # NOTE: Needs verifying.
1.105 + "element" : xml.dom.Node.ELEMENT_NODE,
1.106 + "entity" : xml.dom.Node.ENTITY_NODE,
1.107 + "entity_ref" : xml.dom.Node.ENTITY_REFERENCE_NODE,
1.108 + "notation" : xml.dom.Node.NOTATION_NODE,
1.109 + "pi" : xml.dom.Node.PROCESSING_INSTRUCTION_NODE,
1.110 + "text" : xml.dom.Node.TEXT_NODE
1.111 + }
1.112 +
1.113 + def __init__(self, node, ownerElement=None, doctype=None):
1.114 + self._node = node
1.115 + self.ownerElement = ownerElement
1.116 + self.doctype = doctype
1.117 +
1.118 + def as_native_node(self):
1.119 + return self._node
1.120 +
1.121 + def _ownerDocument(self):
1.122 + return Node(self._node.doc)
1.123 +
1.124 + def _nodeType(self):
1.125 + return self._nodeTypes[self._node.type]
1.126 +
1.127 + def _childNodes(self):
1.128 +
1.129 + # NOTE: Consider a generator instead.
1.130 +
1.131 + child_nodes = []
1.132 + _node = self._node.children
1.133 + while _node is not None:
1.134 + child_nodes.append(Node(_node))
1.135 + _node = _node.next
1.136 + return child_nodes
1.137 +
1.138 + def _attributes(self):
1.139 + return NamedNodeMap(self)
1.140 +
1.141 + def _getNs(self):
1.142 +
1.143 + "Internal namespace information retrieval."
1.144 +
1.145 + try:
1.146 + return self._node.ns()
1.147 + except libxml2.treeError:
1.148 + return None
1.149 +
1.150 + def _namespaceURI(self):
1.151 + ns = self._getNs()
1.152 + if ns is not None:
1.153 + return to_unicode(ns.content)
1.154 + else:
1.155 + return None
1.156 +
1.157 + def _nodeValue(self):
1.158 + return to_unicode(self._node.content)
1.159 +
1.160 + def _prefix(self):
1.161 + ns = self._getNs()
1.162 + if ns is not None:
1.163 + return to_unicode(ns.name)
1.164 + else:
1.165 + return None
1.166 +
1.167 + def _nodeName(self):
1.168 + prefix = self._prefix()
1.169 + if prefix is not None:
1.170 + return prefix + ":" + self._localName()
1.171 + else:
1.172 + return self._localName()
1.173 +
1.174 + def _tagName(self):
1.175 + if self._node.type == "element":
1.176 + return self._nodeName()
1.177 + else:
1.178 + return None
1.179 +
1.180 + def _localName(self):
1.181 + return to_unicode(self._node.name)
1.182 +
1.183 + def _parentNode(self):
1.184 + if self.nodeType == xml.dom.Node.DOCUMENT_NODE:
1.185 + return None
1.186 + else:
1.187 + return Node(self._node.parent)
1.188 +
1.189 + def _nextSibling(self):
1.190 + if self._node.next is not None:
1.191 + return Node(self._node.next)
1.192 + else:
1.193 + return None
1.194 +
1.195 + def hasAttributeNS(self, ns, localName):
1.196 + return self.getAttributeNS(ns, localName) is not None
1.197 +
1.198 + def hasAttribute(self, name):
1.199 + return self.getAttribute(name) is not None
1.200 +
1.201 + def getAttributeNS(self, ns, localName):
1.202 + return to_unicode(self._node.nsProp(localName, ns))
1.203 +
1.204 + def getAttribute(self, name):
1.205 + return to_unicode(self._node.prop(name))
1.206 +
1.207 + def getAttributeNodeNS(self, ns, localName):
1.208 + return self.attributes[(ns, localName)]
1.209 +
1.210 + def getAttributeNode(self, localName):
1.211 + # NOTE: Needs verifying.
1.212 + return self.attributes[(None, localName)]
1.213 +
1.214 + def setAttributeNS(self, ns, name, value):
1.215 + # NOTE: Need to convert from Unicode.
1.216 + ns, name, value = map(from_unicode, [ns, name, value])
1.217 +
1.218 + prefix, localName = _get_prefix_and_localName(name)
1.219 + if prefix is not None:
1.220 + self._node.setNsProp(self._node.newNs(ns, prefix), localName, value)
1.221 + elif ns == self._node.ns().content:
1.222 + self._node.setNsProp(self._node.ns().content, localName, value)
1.223 + else:
1.224 + # NOTE: Needs verifying: what should happen to the namespace?
1.225 + self._node.setNsProp(None, localName, value)
1.226 +
1.227 + def setAttribute(self, name, value):
1.228 + # NOTE: Need to convert from Unicode.
1.229 + name, value = map(from_unicode, [name, value])
1.230 +
1.231 + self._node.setProp(name, value)
1.232 +
1.233 + def setAttributeNodeNS(self, ns, name, node):
1.234 + # NOTE: Not actually putting the node on the element.
1.235 + self.setAttributeNS(ns, name, node.nodeValue)
1.236 +
1.237 + def setAttributeNode(self, name, node):
1.238 + # NOTE: Not actually putting the node on the element.
1.239 + self.setAttribute(name, node.nodeValue)
1.240 +
1.241 + def createElementNS(self, ns, name):
1.242 + # NOTE: Need to convert from Unicode.
1.243 + ns, name = map(from_unicode, [ns, name])
1.244 +
1.245 + prefix, localName = _get_prefix_and_localName(name)
1.246 + _node = libxml2.newNode(localName)
1.247 + _ns = _node.newNs(ns, prefix)
1.248 + _node.setNs(_ns)
1.249 + return Node(_node)
1.250 +
1.251 + def createElement(self, name):
1.252 + # NOTE: Need to convert from Unicode.
1.253 + name = from_unicode(name)
1.254 +
1.255 + _node = libxml2.newNode(localName)
1.256 + return Node(_node)
1.257 +
1.258 + def createAttributeNS(self, ns, name):
1.259 + # NOTE: Need to convert from Unicode.
1.260 + ns, name = map(from_unicode, [ns, name])
1.261 +
1.262 + prefix, localName = _get_prefix_and_localName(name)
1.263 + return TemporaryNode(ns, name, xml.dom.Node.ATTRIBUTE_NODE)
1.264 +
1.265 + def createAttribute(self, name):
1.266 + # NOTE: Need to convert from Unicode.
1.267 + name = from_unicode(name)
1.268 +
1.269 + return TemporaryNode(ns, name, xml.dom.Node.ATTRIBUTE_NODE)
1.270 +
1.271 + def createTextNode(self, value):
1.272 + # NOTE: Need to convert from Unicode.
1.273 + name = from_unicode(name)
1.274 +
1.275 + return Node(libxml2.newText(value))
1.276 +
1.277 + def _add_node(self, tmp):
1.278 + if tmp.nodeType == xml.dom.Node.ATTRIBUTE_NODE:
1.279 + if tmp.ns is not None:
1.280 + _child = self._node.newNsProp(None, tmp.localName, None)
1.281 + _ns = _child.newNs(tmp.ns, tmp.prefix)
1.282 + _child.setNs(_ns)
1.283 + else:
1.284 + _child = self._node.newProp(None, tmp.name, None)
1.285 + else:
1.286 + _child = None
1.287 +
1.288 + return _child
1.289 +
1.290 + def importNode(self, node, deep):
1.291 +
1.292 + if node.nodeType == xml.dom.Node.ELEMENT_NODE:
1.293 + imported_element = self.ownerDocument.createElementNS(node.namespaceURI, node.tagName)
1.294 + for value in node.attributes.values():
1.295 + imported_element.setAttributeNS(value.namespaceURI, value.nodeName, value.nodeValue)
1.296 +
1.297 + if deep:
1.298 + for child in node.childNodes:
1.299 + imported_child = self.importNode(child, deep)
1.300 + if imported_child:
1.301 + imported_element.appendChild(imported_child)
1.302 +
1.303 + return imported_element
1.304 +
1.305 + elif node.nodeType == xml.dom.Node.TEXT_NODE:
1.306 + return self.ownerDocument.createTextNode(node.nodeValue)
1.307 +
1.308 + elif node.nodeType == xml.dom.Node.ATTRIBUTE_NODE:
1.309 + return self.ownerDocument.createAttributeNS(node.namespaceURI, node.name)
1.310 +
1.311 + raise ValueError, node.nodeType
1.312 +
1.313 + def insertBefore(self, tmp, oldNode):
1.314 + if tmp.nodeType == xml.dom.Node.TEXT_NODE:
1.315 + _child = tmp._node
1.316 + elif tmp.nodeType == xml.dom.Node.ELEMENT_NODE:
1.317 + _child = tmp._node
1.318 + else:
1.319 + _child = self._add_node(tmp)
1.320 + _child.unlinkNode()
1.321 + return Node(oldNode._node.addPrevSibling(_child))
1.322 +
1.323 + def replaceChild(self, tmp, oldNode):
1.324 + if tmp.nodeType == xml.dom.Node.TEXT_NODE:
1.325 + _child = tmp._node
1.326 + elif tmp.nodeType == xml.dom.Node.ELEMENT_NODE:
1.327 + _child = tmp._node
1.328 + else:
1.329 + _child = self._add_node(tmp)
1.330 + _child.unlinkNode()
1.331 + return Node(oldNode._node.replaceNode(_child))
1.332 +
1.333 + def appendChild(self, tmp):
1.334 + if tmp.nodeType == xml.dom.Node.TEXT_NODE:
1.335 + _child = self._node.addChild(tmp._node)
1.336 + elif tmp.nodeType == xml.dom.Node.ELEMENT_NODE:
1.337 + _child = self._node.addChild(tmp._node)
1.338 + else:
1.339 + _child = self._add_node(tmp)
1.340 + return Node(_child)
1.341 +
1.342 + def removeChild(self, tmp):
1.343 + tmp._node.unlinkNode()
1.344 +
1.345 + #doctype defined in __init__
1.346 + #ownerElement defined in __init__
1.347 + ownerDocument = property(_ownerDocument)
1.348 + childNodes = property(_childNodes)
1.349 + value = data = nodeValue = property(_nodeValue)
1.350 + name = nodeName = property(_nodeName)
1.351 + tagName = property(_tagName)
1.352 + namespaceURI = property(_namespaceURI)
1.353 + prefix = property(_prefix)
1.354 + localName = property(_localName)
1.355 + parentNode = property(_parentNode)
1.356 + nodeType = property(_nodeType)
1.357 + attributes = property(_attributes)
1.358 + nextSibling = property(_nextSibling)
1.359 +
1.360 + def isSameNode(self, other):
1.361 + return self._node.nodePath() == other._node.nodePath()
1.362 +
1.363 + def __eq__(self, other):
1.364 + return self._node.nodePath() == other._node.nodePath()
1.365 +
1.366 +# Utility functions.
1.367 +
1.368 +def createDocumentType(localName, publicId, systemId):
1.369 + return None
1.370 +
1.371 +def createDocument(namespaceURI, localName, doctype):
1.372 + # NOTE: Fixed to use version 1.0 only.
1.373 + d = Node(libxml2.newDoc("1.0"), doctype=doctype)
1.374 + if localName is not None:
1.375 + root = d.createElementNS(namespaceURI, localName)
1.376 + d.appendChild(root)
1.377 + return d
1.378 +
1.379 +def parse(stream_or_string):
1.380 + if hasattr(stream_or_string, "read"):
1.381 + stream = stream_or_string
1.382 + else:
1.383 + stream = open(stream_or_string)
1.384 + return parseString(stream.read())
1.385 +
1.386 +def parseString(s):
1.387 + return Node(libxml2.parseDoc(s))
1.388 +
1.389 +def parseURI(uri):
1.390 + return Node(libxml2.parseURI(uri))
1.391 +
1.392 +def toString(node):
1.393 + return node.as_native_node().serialize()
1.394 +
1.395 +def toStream(node, stream=None):
1.396 + stream = stream or sys.stdout
1.397 + stream.write(toString(node))
1.398 +
1.399 +# vim: tabstop=4 expandtab shiftwidth=4