1
require 'rexml/parsers/baseparser'
2
require 'rexml/parseexception'
3
require 'rexml/namespace'
11
@parser = BaseParser.new(source)
15
@has_listeners = false
24
def add_listener( listener )
25
@parser.add_listener( listener )
30
# Symbol, Array, Block
31
# Listen to Symbol events on Array elements
33
# Listen to Symbol events
35
# Listen to all events on Array elements
37
# Listen to :start_element events on Array elements
39
# Listen to All events
41
# Symbol can be one of: :start_element, :end_element,
42
# :start_prefix_mapping, :end_prefix_mapping, :characters,
43
# :processing_instruction, :doctype, :attlistdecl, :elementdecl,
44
# :entitydecl, :notationdecl, :cdata, :xmldecl, :comment
46
# There is an additional symbol that can be listened for: :progress.
47
# This will be called for every event generated, passing in the current
50
# Array contains regular expressions or strings which will be matched
51
# against fully qualified element names.
53
# Listener must implement the methods in SAX2Listener
55
# Block will be passed the same arguments as a SAX2Listener method would
56
# be, where the method name is the same as the matched Symbol.
57
# See the SAX2Listener for more information.
58
def listen( *args, &blok )
59
if args[0].kind_of? Symbol
61
args[1].each { |match| @procs << [args[0], match, blok] }
63
add( [args[0], nil, blok] )
65
elsif args[0].kind_of? Array
67
args[0].each { |match| add( [nil, match, args[1]] ) }
69
args[0].each { |match| add( [ :start_element, match, blok ] ) }
72
add([nil, nil, args[0]])
76
def deafen( listener=nil, &blok )
78
@listeners.delete_if {|item| item[-1] == listener }
79
@has_listeners = false if @listeners.size == 0
81
@procs.delete_if {|item| item[-1] == blok }
86
@procs.each { |sym,match,block| block.call if sym == :start_document }
87
@listeners.each { |sym,match,block|
88
block.start_document if sym == :start_document or sym.nil?
95
handle( :end_document )
100
@tag_stack.push(event[1])
101
# find the observers for namespaces
102
procs = get_procs( :start_prefix_mapping, event[1] )
103
listeners = get_listeners( :start_prefix_mapping, event[1] )
104
if procs or listeners
105
# break out the namespace declarations
106
# The attributes live in event[2]
107
event[2].each {|n, v| event[2][n] = @parser.normalize(v)}
108
nsdecl = event[2].find_all { |n, value| n =~ /^xmlns(:|$)/ }
109
nsdecl.collect! { |n, value| [ n[6..-1], value ] }
110
@namespace_stack.push({})
112
@namespace_stack[-1][n] = v
113
# notify observers of namespaces
114
procs.each { |ob| ob.call( n, v ) } if procs
115
listeners.each { |ob| ob.start_prefix_mapping(n, v) } if listeners
118
event[1] =~ Namespace::NAMESPLIT
121
uri = get_namespace(prefix)
122
# find the observers for start_element
123
procs = get_procs( :start_element, event[1] )
124
listeners = get_listeners( :start_element, event[1] )
126
procs.each { |ob| ob.call( uri, local, event[1], event[2] ) } if procs
127
listeners.each { |ob|
128
ob.start_element( uri, local, event[1], event[2] )
132
event[1] =~ Namespace::NAMESPLIT
135
uri = get_namespace(prefix)
136
# find the observers for start_element
137
procs = get_procs( :end_element, event[1] )
138
listeners = get_listeners( :end_element, event[1] )
140
procs.each { |ob| ob.call( uri, local, event[1] ) } if procs
141
listeners.each { |ob|
142
ob.end_element( uri, local, event[1] )
145
namespace_mapping = @namespace_stack.pop
146
# find the observers for namespaces
147
procs = get_procs( :end_prefix_mapping, event[1] )
148
listeners = get_listeners( :end_prefix_mapping, event[1] )
149
if procs or listeners
150
namespace_mapping.each do |prefix, uri|
151
# notify observers of namespaces
152
procs.each { |ob| ob.call( prefix ) } if procs
153
listeners.each { |ob| ob.end_prefix_mapping(prefix) } if listeners
157
#normalized = @parser.normalize( event[1] )
158
#handle( :characters, normalized )
159
copy = event[1].clone
160
@entities.each { |key, value| copy = copy.gsub("&#{key};", value) }
161
copy.gsub!( Text::NUMERICENTITY ) {|m|
163
m = "0#{m}" if m[0] == ?x
164
[Integer(m)].pack('U*')
166
handle( :characters, copy )
168
@entities[ event[1] ] = event[2] if event.size == 3
170
when :processing_instruction, :comment, :doctype, :attlistdecl,
171
:elementdecl, :cdata, :notationdecl, :xmldecl
174
handle( :progress, @parser.position )
179
def handle( symbol, *arguments )
181
procs = get_procs( symbol, tag )
182
listeners = get_listeners( symbol, tag )
184
procs.each { |ob| ob.call( *arguments ) } if procs
186
l.send( symbol.to_s, *arguments )
190
# The following methods are duplicates, but it is faster than using
192
def get_procs( symbol, name )
193
return nil if @procs.size == 0
194
@procs.find_all do |sym, match, block|
195
#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
197
(sym.nil? or symbol == sym) and
198
((name.nil? and match.nil?) or match.nil? or (
200
(match.kind_of? Regexp and name =~ match)
204
end.collect{|x| x[-1]}
206
def get_listeners( symbol, name )
207
return nil if @listeners.size == 0
208
@listeners.find_all do |sym, match, block|
210
(sym.nil? or symbol == sym) and
211
((name.nil? and match.nil?) or match.nil? or (
213
(match.kind_of? Regexp and name =~ match)
217
end.collect{|x| x[-1]}
221
if pair[-1].respond_to? :call
222
@procs << pair unless @procs.include? pair
224
@listeners << pair unless @listeners.include? pair
225
@has_listeners = true
229
def get_namespace( prefix )
230
uris = (@namespace_stack.find_all { |ns| not ns[prefix].nil? }) ||
231
(@namespace_stack.find { |ns| not ns[nil].nil? })
232
uris[-1][prefix] unless uris.nil? or 0 == uris.size