Twisted XmlStream: How to connect to events? Twisted XmlStream: How to connect to events? xml xml

Twisted XmlStream: How to connect to events?


This is mostly a guess but as far as I know you need to open the stream by sending a stanza without closing it.

In your example when you send <request type='type 01'><content>some request content</content></request> the server sees the <request> stanza as the start document but then you send </request> and the server will see that as the end document.

Basically, your server consumes <request> as the start document and that's also why your xpath, //request/content, will not match, because all that's left of the element is <content>...</content>.

Try sending something like <stream> from the client first, then the two requests and then </stream>.

Also, subclassing XmlStream is fine as long as you make sure you don't override any methods by default.


The "only" relevant component of XmlStream is the SAX parser. Here's how I've implemented an asynchronous SAX parser using XmlStream and only the XML parsing functions:

server.py

from twisted.words.xish.domish import Elementfrom twisted.words.xish.xmlstream import XmlStreamclass XmlServer(XmlStream):    def __init__(self):        XmlStream.__init__(self)    # possibly unnecessary    def dataReceived(self, data):        """ Overload this function to simply pass the incoming data into the XML parser """        try:            self.stream.parse(data)     # self.stream gets created after self._initializestream() is called        except Exception as e:            self._initializeStream()    # reinit the DOM so other XML can be parsed    def onDocumentStart(self, elementRoot):        """ The root tag has been parsed """        print('Root tag: {0}'.format(elementRoot.name))        print('Attributes: {0}'.format(elementRoot.attributes))    def onElement(self, element):        """ Children/Body elements parsed """        print('\nElement tag: {0}'.format(element.name))        print('Element attributes: {0}'.format(element.attributes))        print('Element content: {0}'.format(str(element)))    def onDocumentEnd(self):        """ Parsing has finished, you should send your response now """        response = domish.Element(('', 'response'))        response['type'] = 'type 01'        response.addElement('content', content='some response content')        self.send(response.toXml())

Then you create a Factory class that will produce this Protocol (which you've demonstrated you're capable of). Basically, you will get all your information from the XML in the onDocumentStart and onElement functions and when you've reached the end (ie. onDocumentEnd) you will send a response based on the parsed information. Also, be sure you call self._initializestream() after parsing each XML message or else you'll get an exception. That should serve as a good skeleton for you.

My answers to your questions:

  1. Don't know :)
  2. It's very reasonable. However I usually just subclass XmlStream (which simply inherits from Protocol) and then use a regular Factory object.
  3. This is a good thing to worry about when using Twisted (+1 for you). Using the approach above, you could fire callbacks/errbacks as you parse and hit an element or wait till you get to the end of the XML then fire your callbacks to your hearts desire. I hope that makes sense :/
  4. I've wondered this too actually. I think it has something to do with the applications and protocols that use the XmlStream object (such as Jabber and IRC). Just overload onDocumentEnd and make it do what you want it to do. That's the beauty of OOP.

Reference:

PS

Your problem is quite common and very simple to solve (at least in my opinion) so don't kill yourself trying to learn the Event Dipatcher model. Actually it seems you have a good handle on callbacks and errbacks (aka Deferred), so I suggest you stick to those and avoid the dispatcher.