Created
March 11, 2009 00:15
-
-
Save julien51/77215 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "rubygems" | |
require "nokogiri" | |
require "eventmachine" | |
## | |
# This is the XML SAX Parser that accepts "pushed" content used by Babylon Gem. | |
class XmppParser < Nokogiri::XML::SAX::Document | |
## | |
# Initialize the parser and adds the callback that will be called upen stanza completion | |
def initialize(&callback) | |
@callback = callback | |
super() | |
@parser = Nokogiri::XML::SAX::Parser.new(self) | |
@doc = nil | |
@elem = nil | |
end | |
## | |
# Parses the received data | |
def parse(data) | |
@parser.parse data | |
end | |
## | |
# Called when the document received in the stream is started | |
def start_document | |
@doc = Nokogiri::XML::Document.new | |
end | |
## | |
# Adds characters to the current element (being parsed) | |
def characters(string) | |
@elem.add_child(Nokogiri::XML::Text.new(string, @doc)) | |
end | |
## | |
# Instantiate a new current Element, adds the corresponding attributes and namespaces | |
# The new element is eventually added to a parent element (if present). | |
# If this element is the first element (the root of the document), then instead of adding it to a parent, we add it to the document itself. In this case, the current element will not be terminated, so we activate the callback immediately. | |
def start_element(qname, attributes = []) | |
e = Nokogiri::XML::Element.new(qname, @doc) | |
add_namespaces_and_attributes_to_node(attributes, e) | |
# Adding the newly created element to the @elem that is being parsed, or, if no element is being parsed, then we set the @root and the @elem to be this newly created element. | |
@elem = @elem ? @elem.add_child(e) : (@root = e) | |
if @elem.name == "stream:stream" | |
# Should be called only for stream:stream. | |
# We re-initialize the document and set its root to be the doc. | |
# Also, we activate the callback since this element will never end. | |
@doc = Nokogiri::XML::Document.new | |
@doc.root = @root = @elem | |
@callback.call(@elem) | |
end | |
end | |
## | |
# Terminates the current element and calls the callback | |
# | |
# BUG : We might have a problem of missed stanzas : (this was taken from the log, the second iq stanza hasn't been parsed!) | |
# DEBUG BABYLON: RECEIVED : <iq from='[email protected]/babylon_client_6970' to='firehoser.superfeedr.com' type='set' id='1419'> | |
# <pubsub xmlns='http://jabber.org/protocol/pubsub'> | |
# <subscribe jid='[email protected]' node='http://feeds2.feedburner.com/NotifixiousFoundersBlog'/> | |
# </pubsub> | |
# </iq><iq from='[email protected]/babylon_client_6970' to='firehoser.superfeedr.com' type='set' id='7858'> | |
# <pubsub xmlns='http://jabber.org/protocol/pubsub'> | |
# <unsubscribe jid='[email protected]' node='http://feeds2.feedburner.com/NotifixiousFoundersBlog'/> | |
# </pubsub> | |
# </iq> | |
# DEBUG BABYLON: PARSED : <iq from="[email protected]/babylon_client_6970" to="firehoser.superfeedr.com" type="set" id="1419"> | |
# <pubsub xmlns:xmlns="http://jabber.org/protocol/pubsub" xmlns:http://jabber.org/protocol/pubsub="xmlns"> | |
# <subscribe jid="[email protected]" node="http://feeds2.feedburner.com/NotifixiousFoundersBlog"/> | |
# </pubsub> | |
# </iq> | |
# INFO BABYLON: ROUTING TO SubscriptionsController::subscribe | |
def end_element(name) | |
if @elem | |
if @elem.parent == @root | |
@callback.call(@elem) | |
# And we also need to remove @elem from its tree | |
@elem.unlink | |
# And the current elem is the next sibling or the root | |
@elem = @root | |
else | |
@elem = @elem.parent | |
end | |
end | |
end | |
private | |
## | |
# Adds namespaces and attributes. Nokogiri passes them as a array of [name, value, name, value]... | |
def add_namespaces_and_attributes_to_node(attrs, node) | |
(attrs.size / 2).times do |i| | |
name, value = attrs[2 * i], attrs[2 * i + 1] | |
if name =~ /xmlns/ | |
node.add_namespace(name, value) | |
else | |
node.set_attribute name, value | |
end | |
end | |
end | |
end | |
# We're simulating an XMPP session to show that the last element it not parsed correctly... | |
content = ["<?xml version='1.0'?><stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:component:accept' id='314321979' from='superfeedr.com'>", | |
"<handshake/>", | |
"<iq from='[email protected]/babylon_client_6970' to='firehoser.superfeedr.com' type='set' id='1419'> | |
<pubsub xmlns='http://jabber.org/protocol/pubsub'> | |
<subscribe jid='[email protected]' node='http://feeds2.feedburner.com/NotifixiousFoundersBlog'/> | |
</pubsub> | |
</iq><iq from='[email protected]/babylon_client_6970' to='firehoser.superfeedr.com' type='set' id='7858'> | |
<pubsub xmlns='http://jabber.org/protocol/pubsub'> | |
<unsubscribe jid='[email protected]' node='http://feeds2.feedburner.com/NotifixiousFoundersBlog'/> | |
</pubsub> | |
</iq>"] | |
@parser = XmppParser.new do |element| | |
puts "=========" | |
puts "PARSED : " | |
puts "#{element} " | |
puts "" | |
end | |
EM.run do | |
index = 0 | |
EM.add_periodic_timer(1) { | |
if index < content.size | |
@parser.parse(content[index]) | |
index = index + 1 | |
else | |
EM.stop_event_loop | |
end | |
} | |
end | |
# Actual output is : | |
# $ ruby saxparser.rb | |
# ========= | |
# PARSED : | |
# <stream:stream xmlns:xmlns:stream="http://etherx.jabber.org/streams" xmlns:xmlns="jabber:component:accept" xmlns:stream:http://etherx.jabber.org/streams="xmlns:stream" xmlns:jabber:component:accept="xmlns" id="314321979" from="superfeedr.com"/> | |
# | |
# ========= | |
# PARSED : | |
# <handshake/> | |
# | |
# ========= | |
# PARSED : | |
# <iq from="[email protected]/babylon_client_6970" to="firehoser.superfeedr.com" type="set" id="1419"> | |
# <pubsub xmlns:xmlns="http://jabber.org/protocol/pubsub" xmlns:http://jabber.org/protocol/pubsub="xmlns"> | |
# <subscribe jid="[email protected]" node="http://feeds2.feedburner.com/NotifixiousFoundersBlog"/> | |
# </pubsub> | |
# </iq> | |
# While it should probably be : | |
# $ ruby saxparser.rb | |
# ========= | |
# PARSED : | |
# <stream:stream xmlns:xmlns:stream="http://etherx.jabber.org/streams" xmlns:xmlns="jabber:component:accept" xmlns:stream:http://etherx.jabber.org/streams="xmlns:stream" xmlns:jabber:component:accept="xmlns" id="314321979" from="superfeedr.com"/> | |
# | |
# ========= | |
# PARSED : | |
# <handshake/> | |
# | |
# ========= | |
# PARSED : | |
# <iq from="[email protected]/babylon_client_6970" to="firehoser.superfeedr.com" type="set" id="1419"> | |
# <pubsub xmlns:xmlns="http://jabber.org/protocol/pubsub" xmlns:http://jabber.org/protocol/pubsub="xmlns"> | |
# <subscribe jid="[email protected]" node="http://feeds2.feedburner.com/NotifixiousFoundersBlog"/> | |
# </pubsub> | |
# </iq> | |
# | |
# ========= | |
# PARSED : | |
# <iq from='[email protected]/babylon_client_6970' to='firehoser.superfeedr.com' type='set' id='7858'> | |
# <pubsub xmlns='http://jabber.org/protocol/pubsub'> | |
# <unsubscribe jid='[email protected]' node='http://feeds2.feedburner.com/NotifixiousFoundersBlog'/> | |
# </pubsub> | |
# </iq> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment