Class: Jabber::StreamParser

Inherits:
Object
  • Object
show all
Defined in:
lib/xmpp4r/streamparser.rb

Overview

The StreamParser uses REXML to parse the incoming XML stream of the Jabber protocol and fires XMPPStanza at the Connection instance.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(stream, listener) ⇒ StreamParser

Constructs a parser for the supplied stream (socket input)

stream
IO

Socket input stream

listener
Object.receive(XMPPStanza)

The listener (usually a Jabber::Protocol::Connection instance)


26
27
28
29
30
# File 'lib/xmpp4r/streamparser.rb', line 26

def initialize(stream, listener)
  @stream = stream
  @listener = listener
  @current = nil
end

Instance Attribute Details

#startedObject (readonly)

status if the parser is started


18
19
20
# File 'lib/xmpp4r/streamparser.rb', line 18

def started
  @started
end

Instance Method Details

#parseObject

Begins parsing the XML stream and does not return until the stream closes.


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/xmpp4r/streamparser.rb', line 36

def parse
  @started = false
  begin
    parser = REXML::Parsers::SAX2Parser.new @stream

    parser.listen( :start_element ) do |uri, localname, qname, attributes|
      e = REXML::Element.new(qname)
      if attributes.kind_of? Hash
        unnormalized_attributes = {}
        attributes.each_pair do |key, value|
          unnormalized_attributes[key] = REXML::Text::unnormalize(value)
        end
      elsif attributes.kind_of? Array
        unnormalized_attributes = []
        attributes.each do |value|
          unnormalized_attributes << [value[0], REXML::Text::unnormalize(value[1])]
        end
      end
      
      e.add_attributes unnormalized_attributes
      @current = @current.nil? ? e : @current.add_element(e)

      # Handling <stream:stream> not only when it is being
      # received as a top-level tag but also as a child of the
      # top-level element itself. This way, we handle stream
      # restarts (ie. after SASL authentication).
      if @current.name == 'stream' and @current.parent.nil?
        @started = true
        @listener.receive(@current)
        @current = nil
      end
    end

    parser.listen( :end_element ) do  |uri, localname, qname|
      if qname == 'stream:stream' and @current.nil?
        @started = false
        @listener.parser_end
      else
        @listener.receive(@current) unless @current.parent
        @current = @current.parent
      end
    end

    parser.listen( :end_document ) do
      raise Jabber::ServerDisconnected, "Server Disconnected!"
    end

    parser.listen( :characters ) do | text |
      @current.add(REXML::Text.new(text.to_s, @current.whitespace, nil, true)) if @current
    end

    parser.listen( :cdata ) do | text |
      @current.add(REXML::CData.new(text)) if @current
    end

    parser.parse
  rescue REXML::ParseException => e
    @listener.parse_failure(e)
  end
end