1.1 --- a/libxml2dom/__init__.py Sat May 14 23:30:14 2005 +0000
1.2 +++ b/libxml2dom/__init__.py Sat May 14 23:30:46 2005 +0000
1.3 @@ -4,26 +4,19 @@
1.4 DOM wrapper around libxml2.
1.5 """
1.6
1.7 -__version__ = "0.1.3"
1.8 +__version__ = "0.2"
1.9
1.10 import xml.dom
1.11 import libxml2
1.12 +from libxml2dom.macrolib import *
1.13 +from libxml2dom.macrolib import \
1.14 + createDocument as Node_createDocument, \
1.15 + parseString as Node_parseString, parseURI as Node_parseURI, \
1.16 + parseFile as Node_parseFile, \
1.17 + toString as Node_toString, toStream as Node_toStream, \
1.18 + toFile as Node_toFile
1.19 import sys
1.20
1.21 -# NOTE: libxml2 seems to use UTF-8 throughout.
1.22 -
1.23 -def from_unicode(s):
1.24 - if type(s) == type(u""):
1.25 - return s.encode("utf-8")
1.26 - else:
1.27 - return s
1.28 -
1.29 -def to_unicode(s):
1.30 - if type(s) == type(""):
1.31 - return unicode(s, encoding="utf-8")
1.32 - else:
1.33 - return s
1.34 -
1.35 # NOTE: Consider a generator instead.
1.36
1.37 class NamedNodeMap(object):
1.38 @@ -32,18 +25,10 @@
1.39 self.node = node
1.40
1.41 def getNamedItem(self, name):
1.42 - for attr in self.values():
1.43 - if name == attr.localName:
1.44 - return attr
1.45 - # NOTE: Check exception possibilities here.
1.46 - return None
1.47 + return self.node.getAttributeNode(name)
1.48
1.49 def getNamedItemNS(self, ns, localName):
1.50 - for attr in self.values():
1.51 - if localName == attr.localName and ns == attr.namespaceURI:
1.52 - return attr
1.53 - # NOTE: Check exception possibilities here.
1.54 - return None
1.55 + return self.node.getAttributeNodeNS(ns, localName)
1.56
1.57 def setNamedItem(self, node):
1.58 self.node.setAttributeNode(node.name, node)
1.59 @@ -65,12 +50,7 @@
1.60 pass
1.61
1.62 def values(self):
1.63 - attributes = []
1.64 - _attribute = self.node.as_native_node().properties
1.65 - while _attribute is not None:
1.66 - attributes.append(Node(_attribute, ownerElement=self.node))
1.67 - _attribute = _attribute.next
1.68 - return attributes
1.69 + return [Node(_node) for _node in Node_attributes(self.node.as_native_node()).values()]
1.70
1.71 def keys(self):
1.72 return [(attr.namespaceURI, attr.localName) for attr in self.values()]
1.73 @@ -84,289 +64,135 @@
1.74 def __str__(self):
1.75 return "{%s}" % ",\n".join(["%s : %s" % (repr(key), repr(value)) for key, value in self.items()])
1.76
1.77 -def _get_prefix_and_localName(name):
1.78 - t = name.split(":")
1.79 - if len(t) == 1:
1.80 - return None, name
1.81 - elif len(t) == 2:
1.82 - return t
1.83 - else:
1.84 - # NOTE: Should raise an exception.
1.85 - return None, None
1.86 -
1.87 -class TemporaryNode(object):
1.88 - def __init__(self, ns, name, nodeType):
1.89 - self.ns = ns
1.90 - self.name = name
1.91 - self.nodeType = nodeType
1.92 - self.prefix, self.localName = _get_prefix_and_localName(self.name)
1.93 -
1.94 class Node(object):
1.95
1.96 - _nodeTypes = {
1.97 - "attribute" : xml.dom.Node.ATTRIBUTE_NODE,
1.98 - "comment" : xml.dom.Node.COMMENT_NODE,
1.99 - "document_xml" : xml.dom.Node.DOCUMENT_NODE,
1.100 - "doctype" : xml.dom.Node.DOCUMENT_TYPE_NODE,
1.101 - "dtd" : xml.dom.Node.DOCUMENT_TYPE_NODE, # NOTE: Needs verifying.
1.102 - "element" : xml.dom.Node.ELEMENT_NODE,
1.103 - "entity" : xml.dom.Node.ENTITY_NODE,
1.104 - "entity_ref" : xml.dom.Node.ENTITY_REFERENCE_NODE,
1.105 - "notation" : xml.dom.Node.NOTATION_NODE,
1.106 - "pi" : xml.dom.Node.PROCESSING_INSTRUCTION_NODE,
1.107 - "text" : xml.dom.Node.TEXT_NODE
1.108 - }
1.109 -
1.110 def __init__(self, node, ownerElement=None, doctype=None):
1.111 self._node = node
1.112 - self.ownerElement = ownerElement
1.113 - self.doctype = doctype
1.114
1.115 def as_native_node(self):
1.116 return self._node
1.117
1.118 def _ownerDocument(self):
1.119 - return Node(self._node.doc)
1.120 + return Node(Node_ownerDocument(self._node))
1.121
1.122 def _nodeType(self):
1.123 - return self._nodeTypes[self._node.type]
1.124 + return Node_nodeType(self._node)
1.125
1.126 def _childNodes(self):
1.127
1.128 # NOTE: Consider a generator instead.
1.129
1.130 - child_nodes = []
1.131 - _node = self._node.children
1.132 - while _node is not None:
1.133 - child_nodes.append(Node(_node))
1.134 - _node = _node.next
1.135 - return child_nodes
1.136 + return [Node(_node) for _node in Node_childNodes(self._node)]
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 + return Node_namespaceURI(self._node)
1.157
1.158 def _nodeValue(self):
1.159 - return to_unicode(self._node.content)
1.160 + return Node_nodeValue(self._node)
1.161
1.162 def _prefix(self):
1.163 - ns = self._getNs()
1.164 - if ns is not None:
1.165 - return to_unicode(ns.name)
1.166 - else:
1.167 - return None
1.168 + return Node_prefix(self._node)
1.169
1.170 def _nodeName(self):
1.171 - prefix = self._prefix()
1.172 - if prefix is not None:
1.173 - return prefix + ":" + self._localName()
1.174 - else:
1.175 - return self._localName()
1.176 + return Node_nodeName(self._node)
1.177
1.178 def _tagName(self):
1.179 - if self._node.type == "element":
1.180 - return self._nodeName()
1.181 - else:
1.182 - return None
1.183 + return Node_tagName(self._node)
1.184
1.185 def _localName(self):
1.186 - return to_unicode(self._node.name)
1.187 + return Node_localName(self._node)
1.188
1.189 def _parentNode(self):
1.190 - if self.nodeType == xml.dom.Node.DOCUMENT_NODE:
1.191 - return None
1.192 - else:
1.193 - return Node(self._node.parent)
1.194 + return Node_parentNode(self._node)
1.195
1.196 def _previousSibling(self):
1.197 - if self._node.prev is not None:
1.198 - return Node(self._node.prev)
1.199 - else:
1.200 - return None
1.201 + return Node(Node_previousSibling(self._node))
1.202
1.203 def _nextSibling(self):
1.204 - if self._node.next is not None:
1.205 - return Node(self._node.next)
1.206 - else:
1.207 - return None
1.208 + return Node(Node_nextSibling(self._node))
1.209
1.210 def hasAttributeNS(self, ns, localName):
1.211 - return self.getAttributeNS(ns, localName) is not None
1.212 + return Node_hasAttributeNS(self._node, ns, localName)
1.213
1.214 def hasAttribute(self, name):
1.215 - return self.getAttribute(name) is not None
1.216 + return Node_hasAttribute(self._node, name)
1.217
1.218 def getAttributeNS(self, ns, localName):
1.219 - return to_unicode(self._node.nsProp(localName, ns))
1.220 + return Node_getAttributeNS(self._node, ns, localName)
1.221
1.222 def getAttribute(self, name):
1.223 - return to_unicode(self._node.prop(name))
1.224 + return Node_getAttribute(self._node, name)
1.225
1.226 def getAttributeNodeNS(self, ns, localName):
1.227 - return self.attributes.getNamedItemNS(ns, localName)
1.228 + return Node(Node_getAttributeNodeNS(self._node, ns, localName))
1.229
1.230 def getAttributeNode(self, localName):
1.231 - # NOTE: Needs verifying.
1.232 - return self.attributes.getNamedItem(localName)
1.233 + return Node(Node_getAttributeNode(self._node, localName))
1.234
1.235 def setAttributeNS(self, ns, name, value):
1.236 - # NOTE: Need to convert from Unicode.
1.237 - ns, name, value = map(from_unicode, [ns, name, value])
1.238 -
1.239 - prefix, localName = _get_prefix_and_localName(name)
1.240 - if prefix is not None:
1.241 - self._node.setNsProp(self._node.newNs(ns, prefix), localName, value)
1.242 - elif ns is not None and ns == self._node.ns().content:
1.243 - self._node.setNsProp(self._node.ns(), localName, value)
1.244 - else:
1.245 - # NOTE: Needs verifying: what should happen to the namespace?
1.246 - # NOTE: This also catches the case where None is the element's
1.247 - # NOTE: namespace and is also used for the attribute.
1.248 - self._node.setNsProp(None, localName, value)
1.249 + Node_setAttributeNS(self._node, ns, name, value)
1.250
1.251 def setAttribute(self, name, value):
1.252 - # NOTE: Need to convert from Unicode.
1.253 - name, value = map(from_unicode, [name, value])
1.254 -
1.255 - self._node.setProp(name, value)
1.256 + Node_setAttribute(self._node, name, value)
1.257
1.258 def setAttributeNodeNS(self, ns, name, node):
1.259 - # NOTE: Not actually putting the node on the element.
1.260 - self.setAttributeNS(ns, name, node.nodeValue)
1.261 + Node_setAttributeNodeNS(self._node, ns, name, node)
1.262
1.263 def setAttributeNode(self, name, node):
1.264 - # NOTE: Not actually putting the node on the element.
1.265 - self.setAttribute(name, node.nodeValue)
1.266 + Node_setAttributeNode(self._node, name, node)
1.267
1.268 def createElementNS(self, ns, name):
1.269 - # NOTE: Need to convert from Unicode.
1.270 - ns, name = map(from_unicode, [ns, name])
1.271 -
1.272 - prefix, localName = _get_prefix_and_localName(name)
1.273 - _node = libxml2.newNode(localName)
1.274 - # NOTE: Does it make sense to set the namespace if it is empty?
1.275 - if ns is not None:
1.276 - _ns = _node.newNs(ns, prefix)
1.277 - _node.setNs(_ns)
1.278 - return Node(_node)
1.279 + return Node(Node_createElementNS(self._node, ns, name))
1.280
1.281 def createElement(self, name):
1.282 - # NOTE: Need to convert from Unicode.
1.283 - name = from_unicode(name)
1.284 -
1.285 - _node = libxml2.newNode(name)
1.286 - return Node(_node)
1.287 + return Node(Node_createElement(self._node, name))
1.288
1.289 def createAttributeNS(self, ns, name):
1.290 - # NOTE: Need to convert from Unicode.
1.291 - ns, name = map(from_unicode, [ns, name])
1.292 -
1.293 - prefix, localName = _get_prefix_and_localName(name)
1.294 - return TemporaryNode(ns, name, xml.dom.Node.ATTRIBUTE_NODE)
1.295 + # Returns a special temporary node.
1.296 + return Node_createAttributeNS(self._node, ns, name)
1.297
1.298 def createAttribute(self, name):
1.299 - # NOTE: Need to convert from Unicode.
1.300 - name = from_unicode(name)
1.301 -
1.302 - return TemporaryNode(ns, name, xml.dom.Node.ATTRIBUTE_NODE)
1.303 + # Returns a special temporary node.
1.304 + return Node_createAttribute(self._node, name)
1.305
1.306 def createTextNode(self, value):
1.307 - # NOTE: Need to convert from Unicode.
1.308 - value = from_unicode(value)
1.309 -
1.310 - return Node(libxml2.newText(value))
1.311 + return Node(Node_createTextNode(self._node, value))
1.312
1.313 def createComment(self, value):
1.314 - # NOTE: Need to convert from Unicode.
1.315 - value = from_unicode(value)
1.316 -
1.317 - return Node(libxml2.newComment(value))
1.318 -
1.319 - def _add_node(self, tmp):
1.320 - if tmp.nodeType == xml.dom.Node.ATTRIBUTE_NODE:
1.321 - if tmp.ns is not None:
1.322 - _child = self._node.newNsProp(None, tmp.localName, None)
1.323 - _ns = _child.newNs(tmp.ns, tmp.prefix)
1.324 - _child.setNs(_ns)
1.325 - else:
1.326 - _child = self._node.newProp(None, tmp.name, None)
1.327 - else:
1.328 - _child = None
1.329 -
1.330 - return _child
1.331 + return Node(Node_createComment(self._node, value))
1.332
1.333 def importNode(self, node, deep):
1.334 -
1.335 - if node.nodeType == xml.dom.Node.ELEMENT_NODE:
1.336 - imported_element = self.ownerDocument.createElementNS(node.namespaceURI, node.tagName)
1.337 - for value in node.attributes.values():
1.338 - imported_element.setAttributeNS(value.namespaceURI, value.nodeName, value.nodeValue)
1.339 -
1.340 - if deep:
1.341 - for child in node.childNodes:
1.342 - imported_child = self.importNode(child, deep)
1.343 - if imported_child:
1.344 - imported_element.appendChild(imported_child)
1.345 -
1.346 - return imported_element
1.347 -
1.348 - elif node.nodeType == xml.dom.Node.TEXT_NODE:
1.349 - return self.ownerDocument.createTextNode(node.nodeValue)
1.350 -
1.351 - elif node.nodeType == xml.dom.Node.ATTRIBUTE_NODE:
1.352 - return self.ownerDocument.createAttributeNS(node.namespaceURI, node.name)
1.353 -
1.354 - elif node.nodeType == xml.dom.Node.COMMENT_NODE:
1.355 - return self.ownerDocument.createComment(node.data)
1.356 -
1.357 - raise ValueError, node.nodeType
1.358 + if hasattr(node, "as_native_node"):
1.359 + return Node(Node_importNode(self._node, node.as_native_node(), deep))
1.360 + else:
1.361 + return Node(Node_importNode_DOM(self._node, node, deep))
1.362
1.363 def insertBefore(self, tmp, oldNode):
1.364 - if tmp.nodeType == xml.dom.Node.TEXT_NODE:
1.365 - _child = tmp._node
1.366 - elif tmp.nodeType == xml.dom.Node.ELEMENT_NODE:
1.367 - _child = tmp._node
1.368 + if hasattr(tmp, "as_native_node"):
1.369 + return Node(Node_insertBefore(self._node, tmp.as_native_node(), oldNode.as_native_node()))
1.370 else:
1.371 - _child = self._add_node(tmp)
1.372 - _child.unlinkNode()
1.373 - return Node(oldNode._node.addPrevSibling(_child))
1.374 + return Node(Node_insertBefore(self._node, tmp, oldNode.as_native_node()))
1.375
1.376 def replaceChild(self, tmp, oldNode):
1.377 - if tmp.nodeType == xml.dom.Node.TEXT_NODE:
1.378 - _child = tmp._node
1.379 - elif tmp.nodeType == xml.dom.Node.ELEMENT_NODE:
1.380 - _child = tmp._node
1.381 + if hasattr(tmp, "as_native_node"):
1.382 + return Node(Node_replaceChild(self._node, tmp.as_native_node(), oldNode.as_native_node()))
1.383 else:
1.384 - _child = self._add_node(tmp)
1.385 - _child.unlinkNode()
1.386 - return Node(oldNode._node.replaceNode(_child))
1.387 + return Node(Node_replaceChild(self._node, tmp, oldNode.as_native_node()))
1.388
1.389 def appendChild(self, tmp):
1.390 - if tmp.nodeType == xml.dom.Node.TEXT_NODE:
1.391 - _child = self._node.addChild(tmp._node)
1.392 - elif tmp.nodeType == xml.dom.Node.ELEMENT_NODE:
1.393 - _child = self._node.addChild(tmp._node)
1.394 + if hasattr(tmp, "as_native_node"):
1.395 + return Node(Node_appendChild(self._node, tmp.as_native_node()))
1.396 else:
1.397 - _child = self._add_node(tmp)
1.398 - return Node(_child)
1.399 + return Node(Node_appendChild(self._node, tmp))
1.400
1.401 def removeChild(self, tmp):
1.402 - tmp._node.unlinkNode()
1.403 + if hasattr(tmp, "as_native_node"):
1.404 + Node_removeChild(self._node, tmp.as_native_node())
1.405 + else:
1.406 + Node_removeChild(self._node, tmp)
1.407
1.408 #doctype defined in __init__
1.409 #ownerElement defined in __init__
1.410 @@ -384,23 +210,17 @@
1.411 previousSibling = property(_previousSibling)
1.412 nextSibling = property(_nextSibling)
1.413
1.414 - def isSameNode(self, other):
1.415 - return self._node.nodePath() == other._node.nodePath()
1.416 + #def isSameNode(self, other):
1.417 + # return self._node.nodePath() == other._node.nodePath()
1.418
1.419 - def __eq__(self, other):
1.420 - return self._node.nodePath() == other._node.nodePath()
1.421 + #def __eq__(self, other):
1.422 + # return self._node.nodePath() == other._node.nodePath()
1.423
1.424 # 4DOM extensions to the usual PyXML API.
1.425 # NOTE: To be finished.
1.426
1.427 def xpath(self, expr, variables=None, namespaces=None):
1.428 - context = self.ownerDocument.as_native_node().xpathNewContext()
1.429 - context.setContextNode(self.as_native_node())
1.430 - # NOTE: Discover namespaces from the node.
1.431 - for prefix, ns in (namespaces or {}).items():
1.432 - context.xpathRegisterNs(prefix, ns)
1.433 - # NOTE: May need to tidy up the context.
1.434 - return [Node(_node) for _node in context.xpathEval(expr)]
1.435 + return [Node(_node) for _node in Node_xpath(self._node, expr, variables, namespaces)]
1.436
1.437 # Utility functions.
1.438
1.439 @@ -408,12 +228,7 @@
1.440 return None
1.441
1.442 def createDocument(namespaceURI, localName, doctype):
1.443 - # NOTE: Fixed to use version 1.0 only.
1.444 - d = Node(libxml2.newDoc("1.0"), doctype=doctype)
1.445 - if localName is not None:
1.446 - root = d.createElementNS(namespaceURI, localName)
1.447 - d.appendChild(root)
1.448 - return d
1.449 + return Node(Node_createDocument(namespaceURI, localName, doctype))
1.450
1.451 def parse(stream_or_string):
1.452 if hasattr(stream_or_string, "read"):
1.453 @@ -423,34 +238,21 @@
1.454 return parseFile(stream_or_string)
1.455
1.456 def parseFile(s):
1.457 - # NOTE: Switching off validation and remote DTD resolution.
1.458 - context = libxml2.createFileParserCtxt(s)
1.459 - context.validate(0)
1.460 - context.ctxtUseOptions(0)
1.461 - # Wish context.pedantic(0) would suppress warnings about "DAV:"
1.462 - context.parseDocument()
1.463 - return Node(context.doc())
1.464 + return Node(Node_parseFile(s))
1.465
1.466 def parseString(s):
1.467 - # NOTE: Switching off validation and remote DTD resolution.
1.468 - context = libxml2.createMemoryParserCtxt(s, len(s))
1.469 - context.validate(0)
1.470 - context.ctxtUseOptions(0)
1.471 - # Wish context.pedantic(0) would suppress warnings about "DAV:"
1.472 - context.parseDocument()
1.473 - return Node(context.doc())
1.474 + return Node(Node_parseString(s))
1.475
1.476 def parseURI(uri):
1.477 - return Node(libxml2.parseURI(uri))
1.478 + return Node(Node_parseURI(uri))
1.479
1.480 def toString(node, encoding=None):
1.481 - if encoding is None:
1.482 - return node.as_native_node().serialize()
1.483 - else:
1.484 - return node.as_native_node().serialize(encoding)
1.485 + return Node_toString(node.as_native_node(), encoding)
1.486
1.487 -def toStream(node, stream=None, encoding=None):
1.488 - stream = stream or sys.stdout
1.489 - stream.write(toString(node, encoding))
1.490 +def toStream(node, stream, encoding=None):
1.491 + Node_toStream(node.as_native_node(), stream, encoding)
1.492 +
1.493 +def toFile(node, f, encoding=None):
1.494 + Node_toFile(node.as_native_node(), f, encoding)
1.495
1.496 # vim: tabstop=4 expandtab shiftwidth=4