[Twisted-Python] Help using XmlStreamFactory & XmlStream : XPathQuery error?

Ralph Meijer twisted at ralphm.ik.nu
Wed Feb 20 05:29:37 EST 2008

On Wed, 2008-02-20 at 10:36 +0100, Gabriel Rossetti wrote:
> [..]
> I'm having some trouble with the XPath I think when trying to react on 
> xml messages. I am feeding the twisted.words.xish.xmlstream.XmlStream 
> the following :
>     <?xml version="1.0" encoding="utf-8"?>
>     <test><feed name='monNom'>toto</feed></test>
> and the callback functions are :
>     def onTest(self, element):
>         print "got test : ", element
>     def onFeed(self, element):
>         print "got feed : ", element
>     def onFeedFilteredByName(self, element):
>         print "got feed name : ", element
>     def onWildcard(self, element):
>         print "got wildcard : ", element
> and the bootstrap is added like so :
>     f.addBootstrap(xmlstream.STREAM_START_EVENT, connected)
> and the bootstrap callback is :
>     def connected(self, xs):
>         print 'Connected!'
>         xs.addObserver("/test", self.onTest)
>         xs.addObserver("/test/feed", self.onFeed)
>         xs.addObserver("/test/feed[@name]", self.onFeedFilteredByName)
>         xs.addObserver("/*", self.onWildcard)
> The only one that gets called is "/*". I tested out the others using 
> XPathQuery manually with :
>     xpath.XPathQuery("//feed[@name]").queryForNodes(root)[0]
> root being the above xml, and they work, I can even get the attributes 
> (which is what  I really need to get) like so :
> xpath.XPathQuery("//feed[@name]").queryForNodes(root)[0].getAttribute("name")
> What am I doing wrong when adding observers? How can I get them to react 
> on attribute names too?


A somewhat lengthy explanation follows,

XML Streams are a result of the work on Jabber. As such, the generalized
version of XmlStream in xish works similarly, but without the Jabber
specifics in terms of namespaces and elements. However, the concept
behind XML Streams is that you open the stream with a root element, and
after that the units of exchange are the first-level childs of that root
element, or so-called XML Stanzas.

EventDispatcher, a superclass of XmlStream, is responsible for calling
back observers upon calls to its dispatch method. For each XML Stanza,
XmlStream will dispatch the DOM object at the root of that snippet of
XML (domish.Element) for the XML Stanza. Observers are registered to
XPath (-like) queries to match those Elements.

Now that's out of the way, in your specific example, the <feed/> element
would be an XML Stanza. So you can only register an observer to that,
like this:

   xs.addObserver('/feed', self.onFeed)

If some <feed/>'s would have child <title/>, you could add an observer
on just those <feed/>'s with a title like this:

   xs.addObserver('/feed/title', self.onFeedWithTitle)

The observer would still get the whole <feed/> element passed. So, to be
clear: the XPath-like queries are for matching against XML Stanzas, and
each XML Stanza that matches is then passed to the callbacks registered
to that query.

For completeness, ff you want to hook up an event to the start tag of
the root element having been received, you'd do this:

  xs.addObserver(STREAM_START_EVENT, self.onTest)

In that case, you need to do change the bootstrap registration to this:

  f.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT, connected)

Hope that clears some things up.



More information about the Twisted-Python mailing list