class REXML::Parsers::SAX2Parser

SAX2Parser

公共类方法

new(source) 点击切换源代码
# File rexml-3.4.0/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

公共实例方法

add_listener( listener ) 点击切换源代码
# File rexml-3.4.0/lib/rexml/parsers/sax2parser.rb, line 37
def add_listener( listener )
  @parser.add_listener( listener )
end
deafen( listener=nil, &blok ) 点击切换源代码
# File rexml-3.4.0/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() 点击切换源代码
# File rexml-3.4.0/lib/rexml/parsers/sax2parser.rb, line 25
def entity_expansion_count
  @parser.entity_expansion_count
end
entity_expansion_limit=( limit ) 点击切换源代码
# File rexml-3.4.0/lib/rexml/parsers/sax2parser.rb, line 29
def entity_expansion_limit=( limit )
  @parser.entity_expansion_limit = limit
end
entity_expansion_text_limit=( limit ) 点击切换源代码
# File rexml-3.4.0/lib/rexml/parsers/sax2parser.rb, line 33
def entity_expansion_text_limit=( limit )
  @parser.entity_expansion_text_limit = limit
end
listen( *args, &blok ) 点击切换源代码

Listen 参数

符号,数组,代码块

Listen to Symbol events on Array elements

符号,代码块

Listen to Symbol events

数组,监听器

Listen to all events on Array elements

数组,代码块

Listen to :start_element events on Array elements

监听器

Listen to All events

符号可以是以下之一::start_element、:end_element、:start_prefix_mapping、:end_prefix_mapping、:characters、:processing_instruction、:doctype、:attlistdecl、:elementdecl、:entitydecl、:notationdecl、:cdata、:xmldecl、:comment

还有一个额外的符号可以监听::progress。这将为生成的每个事件调用,传入当前流位置。

数组包含正则表达式或字符串,它们将与完全限定的元素名称进行匹配。

监听器必须实现 SAX2Listener 中的方法

代码块将传递与 SAX2Listener 方法相同的参数,其中方法名称与匹配的符号相同。有关更多信息,请参阅 SAX2Listener

# File rexml-3.4.0/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() 点击切换源代码
# File rexml-3.4.0/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() 点击切换源代码
# File rexml-3.4.0/lib/rexml/parsers/sax2parser.rb, line 21
def source
  @parser.source
end

私有实例方法

add( pair ) 点击切换源代码
# File rexml-3.4.0/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
get_listeners( symbol, name ) 点击切换源代码
# File rexml-3.4.0/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 ) 点击切换源代码
# File rexml-3.4.0/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 ) 点击切换源代码

以下方法是重复的,但比使用辅助方法更快

# File rexml-3.4.0/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 ) 点击切换源代码
# File rexml-3.4.0/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 ) 点击切换源代码
# File rexml-3.4.0/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