Class: REXML::Parsers::SAX2Parser
Relationships & Source Files | |
Inherits: | Object |
Defined in: | lib/rexml/parsers/sax2parser.rb |
Overview
SAX2Parser
Class Method Summary
- .new(source) ⇒ SAX2Parser constructor
Instance Attribute Summary
- #entity_expansion_limit=(limit) writeonly
- #entity_expansion_text_limit=(limit) writeonly
Instance Method Summary
- #add_listener(listener)
- #deafen(listener = nil, &blok)
- #entity_expansion_count
-
#listen(*args, &blok)
Listen arguments:
- #parse
- #source
- #add(pair) private
- #get_listeners(symbol, name) private
- #get_namespace(prefix) private
-
#get_procs(symbol, name)
private
The following methods are duplicates, but it is faster than using a helper.
- #handle(symbol, *arguments) private
- #handle_entitydecl(event) private
Constructor Details
.new(source) ⇒ SAX2Parser
# File 'lib/rexml/parsers/sax2parser.rb', line 11
def initialize source @parser = BaseParser.new(source) @listeners = [] @procs = [] @namespace_stack = [] @has_listeners = false @tag_stack = [] @entities = {} end
Instance Attribute Details
#entity_expansion_limit=(limit) (writeonly)
[ GitHub ]# File 'lib/rexml/parsers/sax2parser.rb', line 29
def entity_expansion_limit=( limit ) @parser.entity_expansion_limit = limit end
#entity_expansion_text_limit=(limit) (writeonly)
[ GitHub ]# File 'lib/rexml/parsers/sax2parser.rb', line 33
def entity_expansion_text_limit=( limit ) @parser.entity_expansion_text_limit = limit end
Instance Method Details
#add(pair) (private)
[ GitHub ]# File 'lib/rexml/parsers/sax2parser.rb', line 252
def add( pair ) if pair[-1].respond_to? :call @procs << pair unless @procs.include? pair else @listeners << pair unless @listeners.include? pair @has_listeners = true end end
#add_listener(listener)
[ GitHub ]# File 'lib/rexml/parsers/sax2parser.rb', line 37
def add_listener( listener ) @parser.add_listener( listener ) end
#deafen(listener = nil, &blok)
[ GitHub ]# File 'lib/rexml/parsers/sax2parser.rb', line 89
def deafen( listener=nil, &blok ) if listener @listeners.delete_if {|item| item[-1] == listener } @has_listeners = false if @listeners.size == 0 else @procs.delete_if {|item| item[-1] == blok } end end
#entity_expansion_count
[ GitHub ]# File 'lib/rexml/parsers/sax2parser.rb', line 25
def entity_expansion_count @parser.entity_expansion_count end
#get_listeners(symbol, name) (private)
[ GitHub ]# File 'lib/rexml/parsers/sax2parser.rb', line 238
def get_listeners( symbol, name ) return nil if @listeners.size == 0 @listeners.find_all do |sym, match, block| ( (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) ) ) ) end.collect{|x| x[-1]} end
#get_namespace(prefix) (private)
[ GitHub ]# File 'lib/rexml/parsers/sax2parser.rb', line 261
def get_namespace( prefix ) return nil if @namespace_stack.empty? uris = (@namespace_stack.find_all { |ns| not ns[prefix].nil? }) || (@namespace_stack.find { |ns| not ns[nil].nil? }) uris[-1][prefix] unless uris.nil? or 0 == uris.size end
#get_procs(symbol, name) (private)
The following methods are duplicates, but it is faster than using a helper
# File 'lib/rexml/parsers/sax2parser.rb', line 225
def get_procs( symbol, name ) return nil if @procs.size == 0 @procs.find_all do |sym, match, block| ( (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) ) ) ) end.collect{|x| x[-1]} end
#handle(symbol, *arguments) (private)
[ GitHub ]# File 'lib/rexml/parsers/sax2parser.rb', line 185
def handle( symbol, *arguments ) tag = @tag_stack[-1] procs = get_procs( symbol, tag ) listeners = get_listeners( symbol, tag ) # notify observers procs.each { |ob| ob.call( *arguments ) } if procs listeners.each { |l| l.send( symbol.to_s, *arguments ) } if listeners end
#handle_entitydecl(event) (private)
[ GitHub ]# File 'lib/rexml/parsers/sax2parser.rb', line 196
def handle_entitydecl( event ) @entities[ event[1] ] = event[2] if event.size == 3 parameter_reference_p = false case event[2] when "SYSTEM" if event.size == 5 if event.last == "%" parameter_reference_p = true else event[4, 0] = "NDATA" end end when "PUBLIC" if event.size == 6 if event.last == "%" parameter_reference_p = true else event[5, 0] = "NDATA" end end else parameter_reference_p = (event.size == 4) end event[1, 0] = event.pop if parameter_reference_p handle( event[0], event[1..-1] ) end
#listen(*args, &blok)
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 ::REXML::SAX2Listener
Block will be passed the same arguments as a ::REXML::SAX2Listener
method would be, where the method name is the same as the matched Symbol. See the ::REXML::SAX2Listener
for more information.
# File 'lib/rexml/parsers/sax2parser.rb', line 71
def listen( *args, &blok ) if args[0].kind_of? Symbol if args.size == 2 args[1].each { |match| @procs << [args[0], match, blok] } else add( [args[0], nil, blok] ) end elsif args[0].kind_of? Array if args.size == 2 args[0].each { |match| add( [nil, match, args[1]] ) } else args[0].each { |match| add( [ :start_element, match, blok ] ) } end else add([nil, nil, args[0]]) end end
#parse
[ GitHub ]# File 'lib/rexml/parsers/sax2parser.rb', line 98
def parse @procs.each { |sym,match,block| block.call if sym == :start_document } @listeners.each { |sym,match,block| block.start_document if sym == :start_document or sym.nil? } context = [] while true event = @parser.pull case event[0] when :end_document handle( :end_document ) break when :start_doctype handle( :doctype, *event[1..-1]) when :end_doctype context = context[1] when :start_element @tag_stack.push(event[1]) # find the observers for namespaces procs = get_procs( :start_prefix_mapping, event[1] ) listeners = get_listeners( :start_prefix_mapping, event[1] ) if procs or listeners # break out the namespace declarations # The attributes live in event[2] event[2].each {|n, v| event[2][n] = @parser.normalize(v)} nsdecl = event[2].find_all { |n, value| n =~ /^xmlns(:|$)/ } nsdecl.collect! { |n, value| [ n[6..-1], value ] } @namespace_stack.push({}) nsdecl.each do |n,v| @namespace_stack[-1][n] = v # notify observers of namespaces procs.each { |ob| ob.call( n, v ) } if procs listeners.each { |ob| ob.start_prefix_mapping(n, v) } if listeners end end event[1] =~ Namespace::NAMESPLIT prefix = $1 local = $2 uri = get_namespace(prefix) # find the observers for start_element procs = get_procs( :start_element, event[1] ) listeners = get_listeners( :start_element, event[1] ) # notify observers procs.each { |ob| ob.call( uri, local, event[1], event[2] ) } if procs listeners.each { |ob| ob.start_element( uri, local, event[1], event[2] ) } if listeners when :end_element @tag_stack.pop event[1] =~ Namespace::NAMESPLIT prefix = $1 local = $2 uri = get_namespace(prefix) # find the observers for start_element procs = get_procs( :end_element, event[1] ) listeners = get_listeners( :end_element, event[1] ) # notify observers procs.each { |ob| ob.call( uri, local, event[1] ) } if procs listeners.each { |ob| ob.end_element( uri, local, event[1] ) } if listeners namespace_mapping = @namespace_stack.pop # find the observers for namespaces procs = get_procs( :end_prefix_mapping, event[1] ) listeners = get_listeners( :end_prefix_mapping, event[1] ) if procs or listeners namespace_mapping.each do |ns_prefix, ns_uri| # notify observers of namespaces procs.each { |ob| ob.call( ns_prefix ) } if procs listeners.each { |ob| ob.end_prefix_mapping(ns_prefix) } if listeners end end when :text unnormalized = @parser.unnormalize( event[1], @entities ) handle( :characters, unnormalized ) when :entitydecl handle_entitydecl( event ) when :processing_instruction, :comment, :attlistdecl, :elementdecl, :cdata, :notationdecl, :xmldecl handle( *event ) end handle( :progress, @parser.position ) end end
#source
[ GitHub ]# File 'lib/rexml/parsers/sax2parser.rb', line 21
def source @parser.source end