1.1 --- a/libxml2dom/__init__.py Fri Apr 06 18:37:16 2007 +0000
1.2 +++ b/libxml2dom/__init__.py Fri Apr 06 18:38:06 2007 +0000
1.3 @@ -20,7 +20,7 @@
1.4 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
1.5 """
1.6
1.7 -__version__ = "0.4.2"
1.8 +__version__ = "0.4.3"
1.9
1.10 from libxml2dom.macrolib import *
1.11 from libxml2dom.macrolib import \
1.12 @@ -30,6 +30,7 @@
1.13 toString as Node_toString, toStream as Node_toStream, \
1.14 toFile as Node_toFile
1.15 import urllib # for parseURI in HTML mode
1.16 +import xml.dom # for getElementById
1.17
1.18 class Implementation(object):
1.19
1.20 @@ -363,6 +364,14 @@
1.21 else:
1.22 Node_removeChild(self._node, tmp)
1.23
1.24 + def getElementById(self, identifier):
1.25 + nodes = self.xpath(".//*[@xml:id='" + identifier.replace("'", "'") + "']",
1.26 + namespaces={"xml" : xml.dom.XML_NAMESPACE})
1.27 + if nodes:
1.28 + return nodes[0]
1.29 + else:
1.30 + return None
1.31 +
1.32 def getElementsByTagName(self, tagName):
1.33 return self.xpath(".//" + tagName)
1.34
1.35 @@ -413,6 +422,9 @@
1.36 def isSameNode(self, other):
1.37 return self == other
1.38
1.39 + def __hash__(self):
1.40 + return hash(self.localName)
1.41 +
1.42 def __eq__(self, other):
1.43 return isinstance(other, Node) and libxml2mod.xmlXPathCmpNodes(self._node, other._node) == 0
1.44
2.1 --- a/libxml2dom/events.py Fri Apr 06 18:37:16 2007 +0000
2.2 +++ b/libxml2dom/events.py Fri Apr 06 18:38:06 2007 +0000
2.3 @@ -21,6 +21,7 @@
2.4 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
2.5 """
2.6
2.7 +import xml.dom
2.8 import time
2.9
2.10 XML_EVENTS_NAMESPACE = "http://www.w3.org/2001/xml-events"
2.11 @@ -32,13 +33,19 @@
2.12
2.13 class DocumentEvent:
2.14
2.15 - "An event interface supportable by documents."
2.16 + """
2.17 + An event interface supportable by documents.
2.18 + See: http://www.w3.org/TR/DOM-Level-3-Events/events.html#Events-DocumentEvent
2.19 + """
2.20
2.21 def canDispatch(self, namespaceURI, type):
2.22 - raise NotImplementedError, "canDispatch"
2.23 + return namespaceURI is None and event_types.has_key(type)
2.24
2.25 def createEvent(self, eventType):
2.26 - raise NotImplementedError, "createEvent"
2.27 + try:
2.28 + return event_types[eventType]()
2.29 + except KeyError:
2.30 + raise xml.dom.DOMException(xml.dom.NOT_SUPPORTED_ERR)
2.31
2.32 class Event:
2.33
2.34 @@ -48,16 +55,15 @@
2.35 AT_TARGET = 2
2.36 BUBBLING_PHASE = 3
2.37
2.38 - def __init__(self, target, currentTarget):
2.39 + def __init__(self):
2.40
2.41 "Initialise the event."
2.42
2.43 - self.target = target
2.44 - self.currentTarget = currentTarget
2.45 - self.defaultPrevented = 0
2.46 -
2.47 # Initialised later:
2.48
2.49 + self.target = None
2.50 + self.currentTarget = None
2.51 + self.defaultPrevented = 0
2.52 self.type = None
2.53 self.namespaceURI = None
2.54
2.55 @@ -85,26 +91,51 @@
2.56 def stopImmediatePropagation(self):
2.57 pass
2.58
2.59 +class UIEvent(Event):
2.60 +
2.61 + "A user interface event."
2.62 +
2.63 + def __init__(self):
2.64 + Event.__init__(self)
2.65 + self.detail = None
2.66 +
2.67 +class MouseEvent(UIEvent):
2.68 +
2.69 + "A mouse-related event."
2.70 +
2.71 + def __init__(self):
2.72 + Event.__init__(self)
2.73 + self.screenX, self.screenY, self.clientX, self.clientY, self.button = None, None, None, None, None
2.74 +
2.75 +# Event types registry.
2.76 +
2.77 +event_types = {
2.78 + "Event" : Event,
2.79 + "UIEvent" : UIEvent,
2.80 + "MouseEvent" : MouseEvent
2.81 + }
2.82 +
2.83 class EventTarget:
2.84
2.85 "An event target class."
2.86
2.87 - def __init__(self):
2.88 - self.listeners = {}
2.89 -
2.90 def addEventListener(self, type, listener, useCapture):
2.91 self.addEventListenerNS(None, type, listener, useCapture)
2.92
2.93 - def addEventListenerNS(self, namespaceURI, type, listener, useCapture):
2.94 - if not self.listeners.has_key((namespaceURI, type)):
2.95 - self.listeners[(namespaceURI, type)] = []
2.96 - self.listeners[(namespaceURI, type)].append((listener, useCapture))
2.97 + def addEventListenerNS(self, namespaceURI, type, listener, useCapture, group=None): # NOTE: group ignored
2.98 + listeners = self.ownerDocument.global_.listeners
2.99 + if not listeners.has_key(self):
2.100 + listeners[self] = {}
2.101 + if not listeners[self].has_key((namespaceURI, type)):
2.102 + listeners[self][(namespaceURI, type)] = []
2.103 + listeners[self][(namespaceURI, type)].append((listener, useCapture))
2.104
2.105 def dispatchEvent(self, evt):
2.106 + listeners = self.ownerDocument.global_.listeners
2.107 if not evt.type:
2.108 raise EventException(EventException.UNSPECIFIED_EVENT_TYPE_ERR)
2.109 # Dispatch on namespaceURI, type.
2.110 - for listener in self.listeners.get((evt.namespaceURI, evt.type), []):
2.111 + for listener, useCapture in listeners.get(self, {}).get((evt.namespaceURI, evt.type), []):
2.112 listener.handleEvent(evt)
2.113 return evt.defaultPrevented
2.114
2.115 @@ -112,10 +143,10 @@
2.116 self.removeEventListenerNS(None, type, listener, useCapture)
2.117
2.118 def removeEventListenerNS(self, namespaceURI, type, listener, useCapture):
2.119 - if self.listeners.has_key((namespaceURI, type)):
2.120 - listeners = self.listeners[(namespaceURI, type)]
2.121 + listeners = self.ownerDocument.global_.listeners
2.122 + if listeners.has_key(self) and listeners[self].has_key((namespaceURI, type)):
2.123 try:
2.124 - listeners.remove((listener, useCapture))
2.125 + listeners[self][(namespaceURI, type)].remove((listener, useCapture))
2.126 except ValueError:
2.127 pass
2.128
3.1 --- a/libxml2dom/svg.py Fri Apr 06 18:37:16 2007 +0000
3.2 +++ b/libxml2dom/svg.py Fri Apr 06 18:38:06 2007 +0000
3.3 @@ -28,6 +28,7 @@
3.4 from libxml2dom.macrolib import \
3.5 createDocument as Node_createDocument
3.6 import xml.dom
3.7 +import urllib
3.8 import math
3.9 import re
3.10
3.11 @@ -80,6 +81,9 @@
3.12 else:
3.13 return libxml2dom.Implementation.get_node(self, _node, context_node)
3.14
3.15 + def get_global(self, doc):
3.16 + return SVGGlobal(doc)
3.17 +
3.18 # Convenience functions.
3.19
3.20 def createSVGDocument(self):
3.21 @@ -141,7 +145,23 @@
3.22 nextElementSibling = property(_nextElementSibling)
3.23 previousElementSibling = property(_previousElementSibling)
3.24
3.25 -class SVGGlobal: # Global, EventListenerInitializer2
3.26 +class EventListenerInitializer2:
3.27 +
3.28 + "An event listener initialisation interface."
3.29 +
3.30 + def initializeEventListeners(self, scriptElement):
3.31 + pass
3.32 +
3.33 + def createEventListener(self, handlerElement):
3.34 + pass
3.35 +
3.36 +class Global:
3.37 +
3.38 + "An empty global interface."
3.39 +
3.40 + pass
3.41 +
3.42 +class SVGGlobal(Global, EventListenerInitializer2):
3.43
3.44 "An SVG global."
3.45
3.46 @@ -151,6 +171,10 @@
3.47
3.48 self.document = document
3.49
3.50 + # Listener management.
3.51 +
3.52 + self.listeners = {}
3.53 +
3.54 def createConnection(self):
3.55 raise NotImplementedError, "createConnection"
3.56
3.57 @@ -161,10 +185,16 @@
3.58 raise NotImplementedError, "gotoLocation"
3.59
3.60 def binaryToString(self, octets, encoding):
3.61 - raise NotImplementedError, "binaryToString"
3.62 + try:
3.63 + return unicode(octets, encoding)
3.64 + except UnicodeDecodeError, exc:
3.65 + raise GlobalException(GlobalException.ENCODING_ERR)
3.66
3.67 def stringToBinary(self, data, encoding):
3.68 - raise NotImplementedError, "stringToBinary"
3.69 + try:
3.70 + return data.encode(encoding)
3.71 + except UnicodeEncodeError, exc:
3.72 + raise GlobalException(GlobalException.ENCODING_ERR)
3.73
3.74 def getURL(self, iri, callback):
3.75
3.76 @@ -183,8 +213,27 @@
3.77 finally:
3.78 f.close()
3.79
3.80 - def postURL(self, iri, data, callback, type, encoding):
3.81 - raise NotImplementedError, "postURL"
3.82 + def postURL(self, iri, data, callback, type=None, encoding=None):
3.83 +
3.84 + # NOTE: Not asynchronous.
3.85 + # NOTE: The urlopen function may not support IRIs.
3.86 + # No exceptions are supposed to be raised, which is a bit nasty.
3.87 +
3.88 + opener = urllib.URLopener()
3.89 + opener.addheader("Content-Type", type or "text/plain")
3.90 + if encoding:
3.91 + opener.addheader("Content-Encoding", encoding)
3.92 + f = opener.open(iri, data)
3.93 + try:
3.94 + try:
3.95 + content = f.read()
3.96 + contentType = f.headers["Content-Type"]
3.97 + callback.operationComplete(AsyncURLStatus(1, contentType, content))
3.98 + except:
3.99 + callback.operationComplete(AsyncURLStatus(0, None, None))
3.100 + finally:
3.101 + f.close()
3.102 + opener.close()
3.103
3.104 def parseXML(self, data, contextDoc):
3.105 doc = parseString(data)
3.106 @@ -641,7 +690,7 @@
3.107 namespaces["svg"] = SVG_NAMESPACE
3.108 return libxml2dom.Node.xpath(self, expr, variables, namespaces)
3.109
3.110 -class SVGDocument(libxml2dom._Document, SVGNode, DocumentEvent, EventTarget):
3.111 +class SVGDocument(libxml2dom._Document, SVGNode, EventTarget, DocumentEvent): # NOTE: The latter is from DOM Level 3 Events.
3.112
3.113 "An SVG-specific document node."
3.114
3.115 @@ -653,12 +702,15 @@
3.116 """
3.117
3.118 libxml2dom._Document.__init__(self, node, impl)
3.119 - self.global_ = SVGGlobal(self) # parent
3.120 + self.global_ = self.impl.get_global(self) # parent
3.121
3.122 class SVGElement(SVGNode, EventTarget, TraitAccess, ElementTraversal): # NOTE: SVGNode instead of Element.
3.123
3.124 "An SVG-specific element."
3.125
3.126 + def __init__(self, *args, **kw):
3.127 + SVGNode.__init__(self, *args, **kw)
3.128 +
3.129 def _id(self):
3.130 return self.getAttribute("id")
3.131
3.132 @@ -763,6 +815,27 @@
3.133 currentTranslate = property(_currentTranslate)
3.134 viewport = property(_viewport)
3.135
3.136 +# Event handler initialisation.
3.137 +
3.138 +def initialiseEvents(doc):
3.139 +
3.140 + """
3.141 + See: http://www.w3.org/TR/SVGMobile12/svgudom.html#svg__EventListenerInitializer2
3.142 + """
3.143 +
3.144 + for script in doc.xpath("//svg:script"):
3.145 + doc.global_.initializeEventListeners(script)
3.146 + for handler in doc.xpath("//svg:handler"):
3.147 + listener = doc.global_.createEventListener(handler)
3.148 +
3.149 + # NOTE: May need to have the event type understood and correctly parameterised.
3.150 +
3.151 + handler.parentNode.addEventListener(
3.152 + handler.getAttributeNS(libxml2dom.events.XML_EVENTS_NAMESPACE, "event"),
3.153 + listener,
3.154 + 0
3.155 + )
3.156 +
3.157 # Utility functions.
3.158
3.159 createDocument = libxml2dom.createDocument
3.160 @@ -771,17 +844,25 @@
3.161 def createSVGDocument():
3.162 return default_impl.createSVGDocument()
3.163
3.164 -def parse(stream_or_string, html=0, htmlencoding=None):
3.165 - return libxml2dom.parse(stream_or_string, html, htmlencoding, default_impl)
3.166 +def parse(stream_or_string, html=0, htmlencoding=None, impl=None):
3.167 + doc = libxml2dom.parse(stream_or_string, html, htmlencoding, impl or default_impl)
3.168 + initialiseEvents(doc)
3.169 + return doc
3.170
3.171 -def parseFile(filename, html=0, htmlencoding=None):
3.172 - return libxml2dom.parseFile(filename, html, htmlencoding, default_impl)
3.173 +def parseFile(filename, html=0, htmlencoding=None, impl=None):
3.174 + doc = libxml2dom.parseFile(filename, html, htmlencoding, impl or default_impl)
3.175 + initialiseEvents(doc)
3.176 + return doc
3.177
3.178 -def parseString(s, html=0, htmlencoding=None):
3.179 - return libxml2dom.parseString(s, html, htmlencoding, default_impl)
3.180 +def parseString(s, html=0, htmlencoding=None, impl=None):
3.181 + doc = libxml2dom.parseString(s, html, htmlencoding, impl or default_impl)
3.182 + initialiseEvents(doc)
3.183 + return doc
3.184
3.185 -def parseURI(uri, html=0, htmlencoding=None):
3.186 - return libxml2dom.parseURI(uri, html, htmlencoding, default_impl)
3.187 +def parseURI(uri, html=0, htmlencoding=None, impl=None):
3.188 + doc = libxml2dom.parseURI(uri, html, htmlencoding, impl or default_impl)
3.189 + initialiseEvents(doc)
3.190 + return doc
3.191
3.192 # Single instance of the implementation.
3.193