Class REXML::Parsers::SAX2Parser
In: lib/rexml/parsers/sax2parser.rb
Parent: Object

Methods

add   add_listener   deafen   get_listeners   get_namespace   get_procs   handle   listen   new   parse  

Public Class methods

[Source]

    # File lib/rexml/parsers/sax2parser.rb, line 10
10:                         def initialize source
11:                                 @parser = BaseParser.new(source)
12:                                 @listeners = []
13:                                 @procs = []
14:                                 @namespace_stack = []
15:                                 @has_listeners = false
16:                                 @tag_stack = []
17:         @entities = {}
18:                         end

Public Instance methods

[Source]

    # File lib/rexml/parsers/sax2parser.rb, line 20
20:       def add_listener( listener )
21:         @parser.add_listener( listener )
22:       end

[Source]

    # File lib/rexml/parsers/sax2parser.rb, line 72
72:                         def deafen( listener=nil, &blok )
73:                                 if listener
74:                                         @listeners.delete_if {|item| item[-1] == listener }
75:                                         @has_listeners = false if @listeners.size == 0
76:                                 else
77:                                         @procs.delete_if {|item| item[-1] == blok }
78:                                 end
79:                         end

Listen arguments:

Symbol, Array, Block

   Listen to Symbol events on Array elements

Symbol, Block

  Listen to Symbol events

Array, Listener

   Listen to all events on Array elements

Array, Block

   Listen to :start_element events on Array elements

Listener

   Listen to All events

Symbol can be one of: :start_element, :end_element, :start_prefix_mapping, :end_prefix_mapping, :characters, :processing_instruction, :doctype, :attlistdecl, :elementdecl, :entitydecl, :notationdecl, :cdata, :xmldecl, :comment

There is an additional symbol that can be listened for: :progress. This will be called for every event generated, passing in the current stream position.

Array contains regular expressions or strings which will be matched against fully qualified element names.

Listener must implement the methods in SAX2Listener

Block will be passed the same arguments as a SAX2Listener method would be, where the method name is the same as the matched Symbol. See the SAX2Listener for more information.

[Source]

    # File lib/rexml/parsers/sax2parser.rb, line 54
54:                         def listen( *args, &blok )
55:                                 if args[0].kind_of? Symbol
56:                                         if args.size == 2
57:                                                 args[1].each { |match| @procs << [args[0], match, blok] }
58:                                         else
59:                                                 add( [args[0], nil, blok] )
60:                                         end
61:                                 elsif args[0].kind_of? Array
62:                                         if args.size == 2
63:                                                 args[0].each { |match| add( [nil, match, args[1]] ) }
64:                                         else
65:                                                 args[0].each { |match| add( [ :start_element, match, blok ] ) }
66:                                         end
67:                                 else
68:                                         add([nil, nil, args[0]])
69:                                 end
70:                         end

[Source]

     # File lib/rexml/parsers/sax2parser.rb, line 81
 81:                         def parse
 82:                                 @procs.each { |sym,match,block| block.call if sym == :start_document }
 83:                                 @listeners.each { |sym,match,block| 
 84:                                         block.start_document if sym == :start_document or sym.nil?
 85:                                 }
 86:                                 root = context = []
 87:                                 while true
 88:                                         event = @parser.pull
 89:                                         case event[0]
 90:                                         when :end_document
 91:                                                 handle( :end_document )
 92:                                                 break
 93:                                         when :end_doctype
 94:                                                 context = context[1]
 95:                                         when :start_element
 96:                                                 @tag_stack.push(event[1])
 97:                                                 # find the observers for namespaces
 98:                                                 procs = get_procs( :start_prefix_mapping, event[1] )
 99:                                                 listeners = get_listeners( :start_prefix_mapping, event[1] )
100:                                                 if procs or listeners
101:                                                         # break out the namespace declarations
102:                                                         # The attributes live in event[2]
103:                                                         event[2].each {|n, v| event[2][n] = @parser.normalize(v)}
104:                                                         nsdecl = event[2].find_all { |n, value| n =~ /^xmlns(:|$)/ }
105:                                                         nsdecl.collect! { |n, value| [ n[6..-1], value ] }
106:                                                         @namespace_stack.push({})
107:                                                         nsdecl.each do |n,v|
108:                                                                 @namespace_stack[-1][n] = v
109:                                                                 # notify observers of namespaces
110:                                                                 procs.each { |ob| ob.call( n, v ) } if procs
111:                                                                 listeners.each { |ob| ob.start_prefix_mapping(n, v) } if listeners
112:                                                         end
113:                                                 end
114:                                                 event[1] =~ Namespace::NAMESPLIT
115:                                                 prefix = $1
116:                                                 local = $2
117:                                                 uri = get_namespace(prefix)
118:                                                 # find the observers for start_element
119:                                                 procs = get_procs( :start_element, event[1] )
120:                                                 listeners = get_listeners( :start_element, event[1] )
121:                                                 # notify observers
122:                                                 procs.each { |ob| ob.call( uri, local, event[1], event[2] ) } if procs
123:                                                 listeners.each { |ob| 
124:                                                         ob.start_element( uri, local, event[1], event[2] ) 
125:                                                 } if listeners
126:                                         when :end_element
127:                                                 @tag_stack.pop
128:                                                 event[1] =~ Namespace::NAMESPLIT
129:                                                 prefix = $1
130:                                                 local = $2
131:                                                 uri = get_namespace(prefix)
132:                                                 # find the observers for start_element
133:                                                 procs = get_procs( :end_element, event[1] )
134:                                                 listeners = get_listeners( :end_element, event[1] )
135:                                                 # notify observers
136:                                                 procs.each { |ob| ob.call( uri, local, event[1] ) } if procs
137:                                                 listeners.each { |ob| 
138:                                                         ob.end_element( uri, local, event[1] ) 
139:                                                 } if listeners
140: 
141:                                                 namespace_mapping = @namespace_stack.pop
142:                                                 # find the observers for namespaces
143:                                                 procs = get_procs( :end_prefix_mapping, event[1] )
144:                                                 listeners = get_listeners( :end_prefix_mapping, event[1] )
145:                                                 if procs or listeners
146:                                                         namespace_mapping.each do |prefix, uri|
147:                                                                 # notify observers of namespaces
148:                                                                 procs.each { |ob| ob.call( prefix ) } if procs
149:                                                                 listeners.each { |ob| ob.end_prefix_mapping(prefix) } if listeners
150:                                                         end
151:                                                 end
152:                                         when :text
153:             #normalized = @parser.normalize( event[1] )
154:             #handle( :characters, normalized )
155:             copy = event[1].clone
156:             @entities.each { |key, value| copy = copy.gsub("&#{key};", value) }
157:             copy.gsub!( Text::NUMERICENTITY ) {|m|
158:               m=$1
159:               m = "0#{m}" if m[0] == ?x
160:               [Integer(m)].pack('U*')
161:             }
162:             handle( :characters, copy )
163:           when :entitydecl
164:             @entities[ event[1] ] = event[2] if event.size == 3
165:                                                 handle( *event )
166:                                         when :processing_instruction, :comment, :doctype, :attlistdecl, 
167:                                                 :elementdecl, :cdata, :notationdecl, :xmldecl
168:                                                 handle( *event )
169:                                         end
170:           handle( :progress, @parser.position )
171:                                 end
172:                         end

Private Instance methods

[Source]

     # File lib/rexml/parsers/sax2parser.rb, line 216
216:                         def add( pair )
217:                                 if pair[-1].respond_to? :call
218:                                         @procs << pair unless @procs.include? pair
219:                                 else
220:                                         @listeners << pair unless @listeners.include? pair
221:                                         @has_listeners = true
222:                                 end
223:                         end

[Source]

     # File lib/rexml/parsers/sax2parser.rb, line 202
202:                         def get_listeners( symbol, name )
203:                                 return nil if @listeners.size == 0
204:                                 @listeners.find_all do |sym, match, block|
205:                                         (
206:                                                 (sym.nil? or symbol == sym) and 
207:                                                 ((name.nil? and match.nil?) or match.nil? or (
208:                                                         (name == match) or
209:                                                         (match.kind_of? Regexp and name =~ match)
210:                                                         )
211:                                                 )
212:                                         )
213:                                 end.collect{|x| x[-1]}
214:                         end

[Source]

     # File lib/rexml/parsers/sax2parser.rb, line 225
225:                         def get_namespace( prefix ) 
226:         uris = (@namespace_stack.find_all { |ns| not ns[prefix].nil? }) ||
227:                                         (@namespace_stack.find { |ns| not ns[nil].nil? })
228:                                 uris[-1][prefix] unless uris.nil? or 0 == uris.size
229:                         end

The following methods are duplicates, but it is faster than using a helper

[Source]

     # File lib/rexml/parsers/sax2parser.rb, line 188
188:                         def get_procs( symbol, name )
189:                                 return nil if @procs.size == 0
190:                                 @procs.find_all do |sym, match, block|
191:           #puts sym.inspect+"=="+symbol.inspect+ "\t"+match.inspect+"=="+name.inspect+ "\t"+( (sym.nil? or symbol == sym) and ((name.nil? and match.nil?) or match.nil? or ( (name == match) or (match.kind_of? Regexp and name =~ match)))).to_s
192:                                         (
193:                                                 (sym.nil? or symbol == sym) and 
194:                                                 ((name.nil? and match.nil?) or match.nil? or (
195:                                                         (name == match) or
196:                                                         (match.kind_of? Regexp and name =~ match)
197:                                                         )
198:                                                 )
199:                                         )
200:                                 end.collect{|x| x[-1]}
201:                         end

[Source]

     # File lib/rexml/parsers/sax2parser.rb, line 175
175:                         def handle( symbol, *arguments )
176:                                 tag = @tag_stack[-1]
177:                                 procs = get_procs( symbol, tag )
178:                                 listeners = get_listeners( symbol, tag )
179:                                 # notify observers
180:                                 procs.each { |ob| ob.call( *arguments ) } if procs
181:                                 listeners.each { |l| 
182:                                         l.send( symbol.to_s, *arguments ) 
183:                                 } if listeners
184:                         end

[Validate]