diff --git a/src/common/xmpp/simplexml.py b/src/common/xmpp/simplexml.py
index 0c65a0b2f..ad72521cb 100644
--- a/src/common/xmpp/simplexml.py
+++ b/src/common/xmpp/simplexml.py
@@ -49,7 +49,7 @@ class Node(object):
replication (and using replication only to move upwards on the classes tree).
"""
FORCE_NODE_RECREATION=0
- def __init__(self, tag=None, attrs={}, payload=[], parent=None, node=None):
+ def __init__(self, tag=None, attrs={}, payload=[], parent=None, nsp=None, node_built=False, node=None):
""" Takes "tag" argument as the name of node (prepended by namespace, if needed and separated from it
by a space), attrs dictionary as the set of arguments, payload list as the set of textual strings
and child nodes that this node carries within itself and "parent" argument that is another node
@@ -62,22 +62,50 @@ class Node(object):
node=str(node)
if not isinstance(node, Node):
node=NodeBuilder(node,self)
+ node_built = True
else:
- self.name,self.namespace,self.attrs,self.data,self.kids,self.parent = node.name,node.namespace,{},[],[],node.parent
+ self.name,self.namespace,self.attrs,self.data,self.kids,self.parent,self.nsd = node.name,node.namespace,{},[],[],node.parent,{}
for key in node.attrs.keys(): self.attrs[key]=node.attrs[key]
for data in node.data: self.data.append(data)
for kid in node.kids: self.kids.append(kid)
- else: self.name,self.namespace,self.attrs,self.data,self.kids,self.parent = 'tag','',{},[],[],None
-
- if tag: self.namespace, self.name = ([self.namespace]+tag.split())[-2:]
- if parent: self.parent = parent
- if self.parent and not self.namespace: self.namespace=self.parent.namespace
- for attr in attrs.keys():
+ for k,v in node.nsd.items(): self.nsd[k] = v
+ else: self.name,self.namespace,self.attrs,self.data,self.kids,self.parent,self.nsd = 'tag','',{},[],[],None,{}
+ if parent:
+ self.parent = parent
+ self.nsp_cache = {}
+ if nsp:
+ for k,v in nsp.items(): self.nsp_cache[k] = v
+ for attr,val in attrs.items():
+ if attr == 'xmlns':
+ self.nsd[u''] = val
+ elif attr.startswith('xmlns:'):
+ self.nsd[attr[6:]] = val
self.attrs[attr]=attrs[attr]
+ if tag:
+ if node_built:
+ pfx,self.name = (['']+tag.split(':'))[-2:]
+ self.namespace = self.lookup_nsp(pfx)
+ else:
+ if ' ' in tag:
+ self.namespace,self.name = tag.split()
+ else:
+ self.name = tag
if isinstance(payload, basestring): payload=[payload]
for i in payload:
if isinstance(i, Node): self.addChild(node=i)
else: self.data.append(ustr(i))
+
+ def lookup_nsp(self,pfx=''):
+ ns = self.nsd.get(pfx,None)
+ if ns is None:
+ ns = self.nsp_cache.get(pfx,None)
+ if ns is None:
+ if self.parent:
+ ns = self.parent.lookup_nsp(pfx)
+ self.nsp_cache[pfx] = ns
+ else:
+ return 'http://www.gajim.org/xmlns/undeclared'
+ return ns
def __str__(self,fancy=0):
""" Method used to dump node into textual representation.
@@ -85,7 +113,8 @@ class Node(object):
s = (fancy-1) * 2 * ' ' + "<" + self.name
if self.namespace:
if not self.parent or self.parent.namespace!=self.namespace:
- s = s + ' xmlns="%s"'%self.namespace
+ if 'xmlns' not in self.attrs:
+ s = s + ' xmlns="%s"'%self.namespace
for key in self.attrs.keys():
val = ustr(self.attrs[key])
s = s + ' %s="%s"' % ( key, XMLescape(val) )
@@ -111,11 +140,12 @@ class Node(object):
def addChild(self, name=None, attrs={}, payload=[], namespace=None, node=None):
""" If "node" argument is provided, adds it as child node. Else creates new node from
the other arguments' values and adds it as well."""
- if namespace: name=namespace+' '+name
if node:
newnode=node
node.parent = self
else: newnode=Node(tag=name, parent=self, attrs=attrs, payload=payload)
+ if namespace:
+ newnode.setNamespace(namespace)
self.kids.append(newnode)
return newnode
def addData(self, data):
@@ -294,26 +324,25 @@ class NodeBuilder:
"data" (if provided) feeded to parser immidiatedly after instance init.
"""
self.DEBUG(DBG_NODEBUILDER, "Preparing to handle incoming XML stream.", 'start')
- self._parser = xml.parsers.expat.ParserCreate(namespace_separator=' ')
+
+ self._parser = xml.parsers.expat.ParserCreate()
self._parser.StartElementHandler = self.starttag
self._parser.EndElementHandler = self.endtag
self._parser.StartNamespaceDeclHandler = self.handle_namespace_start
self._parser.CharacterDataHandler = self.handle_cdata
self.Parse = self._parser.Parse
-
+
self.__depth = 0
self.__last_depth = 0
self.__max_depth = 0
self._dispatch_depth = 1
self._document_attrs = None
+ self._document_nsp = None
self._mini_dom=initial_node
self.last_is_data = 1
self._ptr=None
self.data_buffer = None
- self.namespaces={"http://www.w3.org/XML/1998/namespace":'xml:'}
- self.xmlns="http://www.w3.org/XML/1998/namespace"
-
- if data:
+ if data:
self._parser.Parse(data,1)
def check_data_buffer(self):
@@ -333,27 +362,29 @@ class NodeBuilder:
def starttag(self, tag, attrs):
"""XML Parser callback. Used internally"""
self.check_data_buffer()
- attlist=attrs.keys() #
- for attr in attlist: # FIXME: Crude hack. And it also slows down the whole library considerably.
- sp=attr.rfind(" ") #
- if sp==-1: continue #
- ns=attr[:sp] #
- attrs[self.namespaces[ns]+attr[sp+1:]]=attrs[attr]
- del attrs[attr] #
self._inc_depth()
self.DEBUG(DBG_NODEBUILDER, "DEPTH -> %i , tag -> %s, attrs -> %s" % (self.__depth, tag, `attrs`), 'down')
if self.__depth == self._dispatch_depth:
if not self._mini_dom :
- self._mini_dom = Node(tag=tag, attrs=attrs)
+ self._mini_dom = Node(tag=tag, attrs=attrs, nsp = self._document_nsp, node_built=True)
else:
- Node.__init__(self._mini_dom,tag=tag, attrs=attrs)
+ Node.__init__(self._mini_dom,tag=tag, attrs=attrs, nsp = self._document_nsp, node_built=True)
self._ptr = self._mini_dom
elif self.__depth > self._dispatch_depth:
- self._ptr.kids.append(Node(tag=tag,parent=self._ptr,attrs=attrs))
+ self._ptr.kids.append(Node(tag=tag,parent=self._ptr,attrs=attrs, node_built=True))
self._ptr = self._ptr.kids[-1]
if self.__depth == 1:
- self._document_attrs = attrs
- ns, name = (['']+tag.split())[-2:]
+ self._document_attrs = {}
+ self._document_nsp = {}
+ nsp, name = (['']+tag.split(':'))[-2:]
+ for attr,val in attrs.items():
+ if attr == 'xmlns':
+ self._document_nsp[u''] = val
+ elif attr.startswith('xmlns:'):
+ self._document_nsp[attr[6:]] = val
+ else:
+ self._document_attrs[attr] = val
+ ns = self._document_nsp.get(nsp, 'http://www.gajim.org/xmlns/undeclared-root')
self.stream_header_received(ns, name, attrs)
if not self.last_is_data and self._ptr.parent:
self._ptr.parent.data.append('')
@@ -383,8 +414,6 @@ class NodeBuilder:
def handle_namespace_start(self, prefix, uri):
"""XML Parser callback. Used internally"""
self.check_data_buffer()
- if prefix: self.namespaces[uri]=prefix+':'
- else: self.xmlns=uri
def DEBUG(self, level, text, comment=None):
""" Gets all NodeBuilder walking events. Can be used for debugging if redefined."""
def getDom(self):
@@ -425,4 +454,4 @@ def BadXML2Node(xml):
tags though. F.e. "some text
some more text" will not work."""
return NodeBuilder(xml).getDom()
-# vim: se ts=3:
\ No newline at end of file
+# vim: se ts=3:
diff --git a/test/test_dispatcher_nb.py b/test/test_dispatcher_nb.py
index cfd90397c..45402f66b 100644
--- a/test/test_dispatcher_nb.py
+++ b/test/test_dispatcher_nb.py
@@ -42,12 +42,12 @@ class TestDispatcherNB(unittest.TestCase):
self.assertEqual(1, len(msgs))
d.ProcessNonBlocking('')
- # we should have been disconnected after that message
- self.assertEqual(1, len(conn.mockGetNamedCalls('pollend')))
+ # we should not have been disconnected after that message
+ self.assertEqual(0, len(conn.mockGetNamedCalls('pollend')))
- # we should not be able to keep parsing
+ # we should be able to keep parsing
d.ProcessNonBlocking('still here?')
- self.assertEqual(1, len(msgs))
+ self.assertEqual(3, len(msgs))
if __name__ == '__main__':
unittest.main()