Merge xmpp.py 4.1 simplexml.py

See #3694


 * WARNING! Incompartible change! Now newtag=n.T.newtag do not creates new tag
but only returns existing one (if possible). If you need to create tag use
either .NT. method or attribute set (i.e. n.T.newtag=something).

 * Added CDATA extracting method to xml node.

 * added xmlns safety check

 * Fixed node attribute deletion with "del node[attr]" syntax.

 * Ordering fix for when addChild and addData are used on the same node (may increase memory usage, might need to watch for that)

 * Fixes for children node fetching, still not perfect, but much better
This commit is contained in:
Stephan Erb 2008-01-18 20:55:18 +00:00
parent 12fc03ecdc
commit 9e74881ed6
5 changed files with 40 additions and 22 deletions

View File

@ -470,8 +470,9 @@ class CommandWindow:
assert action in ('execute', 'prev', 'next', 'complete')
stanza = xmpp.Iq(typ='set', to=self.jid)
cmdnode = stanza.addChild('command', attrs={
'xmlns':xmpp.NS_COMMANDS,
cmdnode = stanza.addChild('command',
namespace=xmpp.NS_COMMANDS,
attrs={
'node':self.commandnode,
'action':action
})
@ -501,8 +502,9 @@ class CommandWindow:
if self.sessionid and self.account.connection:
# we already have sessionid, so the service sent at least one reply.
stanza = xmpp.Iq(typ='set', to=self.jid)
stanza.addChild('command', attrs={
'xmlns':xmpp.NS_COMMANDS,
stanza.addChild('command',
namespace=xmpp.NS_COMMANDS,
attrs={
'node':self.commandnode,
'sessionid':self.sessionid,
'action':'cancel'

View File

@ -45,10 +45,10 @@ class AdHocCommand:
response = request.buildReply('result')
cmd = response.addChild('command', {
'xmlns': xmpp.NS_COMMANDS,
'sessionid': self.sessionid,
'node': self.commandnode,
'status': status})
'status': status},
namespace=xmpp.NS_COMMANDS)
if defaultaction is not None or actions is not None:
if defaultaction is not None:
assert defaultaction in ('cancel', 'execute', 'prev', 'next',

View File

@ -8,7 +8,7 @@ class ConnectionPubSub:
def send_pb_subscription_query(self, jid, cb, *args, **kwargs):
query = xmpp.Iq('get', to=jid)
pb = query.addChild('pubsub', {'xmlns': xmpp.NS_PUBSUB})
pb = query.addChild('pubsub', namespace=xmpp.NS_PUBSUB)
pb.addChild('subscriptions')
id = self.connection.send(query)

View File

@ -286,7 +286,7 @@ class TestCommand(Command_Handler_Prototype):
reply = request.buildReply('result')
form = DataForm(title='Select type of operation',data=['Use the combobox to select the type of calculation you would like to do, then click Next',DataField(name='calctype',label='Calculation Type',value=sessions[session]['data']['type'],options=[['circlediameter','Calculate the Diameter of a circle'],['circlearea','Calculate the area of a circle']],typ='list-single',required=1)])
replypayload = [Node('actions',attrs={'execute':'next'},payload=[Node('next')]),form]
reply.addChild(name='command',attrs={'xmlns':NS_COMMAND,'node':request.getTagAttr('command','node'),'sessionid':session,'status':'executing'},payload=replypayload)
reply.addChild(name='command',namespace=NS_COMMAND,attrs={'node':request.getTagAttr('command','node'),'sessionid':session,'status':'executing'},payload=replypayload)
self._owner.send(reply)
raise NodeProcessed
@ -301,7 +301,7 @@ class TestCommand(Command_Handler_Prototype):
reply = request.buildReply('result')
form = DataForm(title = 'Enter the radius', data=['Enter the radius of the circle (numbers only)',DataField(label='Radius',name='radius',typ='text-single')])
replypayload = [Node('actions',attrs={'execute':'complete'},payload=[Node('complete'),Node('prev')]),form]
reply.addChild(name='command',attrs={'xmlns':NS_COMMAND,'node':request.getTagAttr('command','node'),'sessionid':request.getTagAttr('command','sessionid'),'status':'executing'},payload=replypayload)
reply.addChild(name='command',namespace=NS_COMMAND,attrs={'node':request.getTagAttr('command','node'),'sessionid':request.getTagAttr('command','sessionid'),'status':'executing'},payload=replypayload)
self._owner.send(reply)
raise NodeProcessed
@ -317,13 +317,13 @@ class TestCommand(Command_Handler_Prototype):
result = num*2*pi
reply = result.buildReply(request)
form = DataForm(typ='result',data=[DataField(label='result',name='result',value=result)])
reply.addChild(name='command',attrs={'xmlns':NS_COMMAND,'node':request.getTagAttr('command','node'),'sessionid':request.getTagAttr('command','sessionid'),'status':'completed'},payload=form)
reply.addChild(name='command',namespace=NS_COMMAND,attrs={'node':request.getTagAttr('command','node'),'sessionid':request.getTagAttr('command','sessionid'),'status':'completed'},payload=form)
self._owner.send(reply)
raise NodeProcessed
def cmdCancel(self,conn,request):
reply = request.buildReply('result')
reply.addChild(name='command',attrs={'xmlns':NS_COMMAND,'node':request.getTagAttr('command','node'),'sessionid':request.getTagAttr('command','sessionid'),'status':'cancelled'})
reply.addChild(name='command',namespace=NS_COMMAND,attrs={'node':request.getTagAttr('command','node'),'sessionid':request.getTagAttr('command','sessionid'),'status':'cancelled'})
self._owner.send(reply)
del sessions[request.getTagAttr('command','sessionid')]

View File

@ -12,7 +12,8 @@
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
# $Id: simplexml.py,v 1.27 2005/04/30 07:20:27 snakeru Exp $
# Based on:
# $Id: simplexml.py,v 1.33 2007/09/11 12:46:16 normanr Exp $
"""Simplexml module provides xmpppy library with all needed tools to handle XML nodes and XML streams.
I'm personally using it in many other separate projects. It is designed to be as standalone as possible."""
@ -77,7 +78,7 @@ class Node(object):
if isinstance(payload, basestring): payload=[payload]
for i in payload:
if isinstance(i, Node): self.addChild(node=i)
else: self.data.append(ustr(i))
else: self.addData(i)
def __str__(self,fancy=0):
""" Method used to dump node into textual representation.
@ -96,7 +97,7 @@ class Node(object):
for a in self.kids:
if not fancy and (len(self.data)-1)>=cnt: s=s+XMLescape(self.data[cnt])
elif (len(self.data)-1)>=cnt: s=s+XMLescape(self.data[cnt].strip())
s = s + a.__str__(fancy and fancy+1)
if a: s = s + a.__str__(fancy and fancy+1)
cnt=cnt+1
if not fancy and (len(self.data)-1) >= cnt: s = s + XMLescape(self.data[cnt])
elif (len(self.data)-1) >= cnt: s = s + XMLescape(self.data[cnt].strip())
@ -108,19 +109,36 @@ class Node(object):
s = s + "</" + self.name + ">"
if fancy: s = s + "\n"
return s
def getCDATA(self):
""" Serialise node, dropping all tags and leaving CDATA intact.
That is effectively kills all formatiing, leaving only text were contained in XML.
"""
s = ""
cnt = 0
if self.kids:
for a in self.kids:
s=s+self.data[cnt]
if a: s = s + a.getCDATA()
cnt=cnt+1
if (len(self.data)-1) >= cnt: s = s + self.data[cnt]
return s
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 attrs.has_key('xmlns'):
raise AttributeError("Use namespace=x instead of attrs={'xmlns':x}")
if namespace: name=namespace+' '+name
if node:
newnode=node
node.parent = self
else: newnode=Node(tag=name, parent=self, attrs=attrs, payload=payload)
self.kids.append(newnode)
self.data.append(u'')
return newnode
def addData(self, data):
""" Adds some CDATA to node. """
self.data.append(ustr(data))
self.kids.append(None)
def clearData(self):
""" Removes all CDATA from the node. """
self.data=[]
@ -131,7 +149,7 @@ class Node(object):
""" Deletes the "node" from the node's childs list, if "node" is an instance.
Else deletes the first node that have specified name and (optionally) attributes. """
if not isinstance(node, Node): node=self.getTag(node,attrs)
self.kids.remove(node)
self.kids[self.kids.index(node)]=None
return node
def getAttrs(self):
""" Returns all node's attributes as dictionary. """
@ -160,12 +178,9 @@ class Node(object):
F.e. for "<node>text1<nodea/><nodeb/> text2</node>" will be returned list:
['text1', <nodea instance>, <nodeb instance>, ' text2']. """
ret=[]
for i in range(len(self.kids)+len(self.data)+1):
try:
if self.data[i]: ret.append(self.data[i])
except IndexError: pass
try: ret.append(self.kids[i])
except IndexError: pass
for i in range(max(len(self.data),len(self.kids))):
if i < len(self.data) and self.data[i]: ret.append(self.data[i])
if i < len(self.kids) and self.kids[i]: ret.append(self.kids[i])
return ret
def getTag(self, name, attrs={}, namespace=None):
""" Filters all child nodes using specified arguments as filter.
@ -195,6 +210,7 @@ class Node(object):
def iterTags(self, name, attrs={}, namespace=None):
""" Iterate over all children using specified arguments as filter. """
for node in self.kids:
if not node: continue
if namespace is not None and namespace!=node.getNamespace(): continue
if node.getName() == name:
for key in attrs.keys():
@ -266,7 +282,7 @@ class Node(object):
class T:
""" Auxiliary class used to quick access to node's child nodes. """
def __init__(self,node): self.__dict__['node']=node
def __getattr__(self,attr): return self.node.setTag(attr)
def __getattr__(self,attr): return self.node.getTag(attr)
def __setattr__(self,attr,val):
if isinstance(val,Node): Node.__init__(self.node.setTag(attr),node=val)
else: return self.node.setTagData(attr,val)