Module: Rfm::SaxParser::Handler
- Defined in:
- lib/rfm/utilities/sax_parser.rb
Overview
A handler instance is created for each parsing run. The handler has several important functions:
-
Receive callbacks from the sax/stream parsing engine (start_element, end_element, attribute…).
-
Maintain a stack of cursors, growing & shrinking, throughout the parsing run.
-
Maintain a Cursor instance throughout the parsing run.
-
Hand over parser callbacks & data to the Cursor instance for refined processing.
The handler instance is unique to each different parsing gem but inherits generic methods from this Handler module. During each parsing run, the Hander module creates a new instance of the spcified parer’s handler class and runs the handler’s main parsing method. At the end of the parsing run the handler instance, along with it’s newly parsed object, is returned to the object that originally called for the parsing run (your script/app/whatever).
Instance Attribute Summary collapse
-
#stack ⇒ Object
Returns the value of attribute stack.
-
#template ⇒ Object
Returns the value of attribute template.
Class Method Summary collapse
-
.build(io, template = nil, initial_object = nil, parser = nil, options = {}) ⇒ Object
Main parsing interface (also aliased at SaxParser.parse).
-
.decide_backend ⇒ Object
Finds a loadable backend and returns its symbol.
-
.get_backend(parser = backend) ⇒ Object
Takes backend symbol and returns custom Handler class for specified backend.
Instance Method Summary collapse
-
#_attribute(name, value, *args) ⇒ Object
Add attribute to existing element.
- #_doctype(*args) ⇒ Object
-
#_end_element(tag, *args) ⇒ Object
Close out an existing element.
-
#_start_element(tag, attributes = nil, *args) ⇒ Object
Add a node to an existing element.
-
#_text(value, *args) ⇒ Object
Add ‘content’ attribute to existing element.
- #cursor ⇒ Object
- #dump_cursor ⇒ Object
- #element_buffer? ⇒ Boolean
-
#get_template(name) ⇒ Object
Takes string, symbol, hash, and returns a (possibly cached) parsing template.
- #init_element_buffer ⇒ Object
-
#initialize(_template = nil, initial_object = nil) ⇒ Object
Instance Methods ###.
-
#load_template(dat) ⇒ Object
Does the heavy-lifting of template retrieval.
- #result ⇒ Object
- #send_element_buffer ⇒ Object
-
#set_cursor(args) ⇒ Object
cursor_object.
- #top ⇒ Object
- #transform(name) ⇒ Object
Instance Attribute Details
#stack ⇒ Object
Returns the value of attribute stack.
463 464 465 |
# File 'lib/rfm/utilities/sax_parser.rb', line 463 def stack @stack end |
#template ⇒ Object
Returns the value of attribute template.
463 464 465 |
# File 'lib/rfm/utilities/sax_parser.rb', line 463 def template @template end |
Class Method Details
.build(io, template = nil, initial_object = nil, parser = nil, options = {}) ⇒ Object
Main parsing interface (also aliased at SaxParser.parse)
471 472 473 474 475 476 |
# File 'lib/rfm/utilities/sax_parser.rb', line 471 def self.build(io, template=nil, initial_object=nil, parser=nil, ={}) parser = parser || [:parser] || backend parser = get_backend(parser) (Rfm.log.info "Using backend parser: #{parser}, with template: #{template}") if [:log_parser] parser.build(io, template, initial_object) end |
.decide_backend ⇒ Object
Finds a loadable backend and returns its symbol.
500 501 502 503 504 505 |
# File 'lib/rfm/utilities/sax_parser.rb', line 500 def self.decide_backend #BACKENDS.find{|b| !Gem::Specification::find_all_by_name(b[1]).empty? || b[0]==:rexml}[0] PARSERS.find{|k,v| !Gem::Specification::find_all_by_name(v[:file]).empty? || k == :rexml}[0] rescue raise "The xml parser could not find a loadable backend library: #{$!}" end |
.get_backend(parser = backend) ⇒ Object
Takes backend symbol and returns custom Handler class for specified backend.
488 489 490 491 492 493 494 495 496 497 |
# File 'lib/rfm/utilities/sax_parser.rb', line 488 def self.get_backend(parser=backend) (parser = decide_backend) unless parser if parser.is_a?(String) || parser.is_a?(Symbol) parser_proc = PARSERS[parser.to_sym][:proc] parser_proc.call unless parser_proc.nil? || const_defined?((parser.to_s.capitalize + 'Handler').to_sym) SaxParser.const_get(parser.to_s.capitalize + "Handler") end rescue raise "Could not load the backend parser '#{parser}': #{$!}" end |
Instance Method Details
#_attribute(name, value, *args) ⇒ Object
Add attribute to existing element.
625 626 627 628 629 630 |
# File 'lib/rfm/utilities/sax_parser.rb', line 625 def _attribute(name, value, *args) #puts "Receiving attribute '#{name}' with value '#{value}'" name = transform name new_att = default_class.new.tap{|att| att[name]=value} @element_buffer[:attributes].merge!(new_att) end |
#_doctype(*args) ⇒ Object
647 648 649 650 651 |
# File 'lib/rfm/utilities/sax_parser.rb', line 647 def _doctype(*args) (args = args[0].gsub(/"/, '').split) if args.size ==1 _start_element('doctype', :value=>args) _end_element('doctype') end |
#_end_element(tag, *args) ⇒ Object
Close out an existing element.
640 641 642 643 644 645 |
# File 'lib/rfm/utilities/sax_parser.rb', line 640 def _end_element(tag, *args) tag = transform tag #puts "Receiving end_element '#{tag}'" send_element_buffer cursor.receive_end_element(tag) and dump_cursor end |
#_start_element(tag, attributes = nil, *args) ⇒ Object
Add a node to an existing element.
609 610 611 612 613 614 615 616 617 618 619 620 621 622 |
# File 'lib/rfm/utilities/sax_parser.rb', line 609 def _start_element(tag, attributes=nil, *args) #puts ["_START_ELEMENT", tag, attributes, args].to_yaml # if tag.to_s.downcase=='fmrestulset' tag = transform tag send_element_buffer if element_buffer? if attributes # This crazy thing transforms attribute keys to underscore (or whatever). #attributes = default_class[*attributes.collect{|k,v| [transform(k),v] }.flatten] # This works but downcases all attribute names - not good. attributes = default_class.new.tap {|hash| attributes.each {|k, v| hash[transform(k)] = v}} # This doesn't work yet, but at least it wont downcase hash keys. #attributes = Hash.new.tap {|hash| attributes.each {|k, v| hash[transform(k)] = v}} end @element_buffer.merge!({:tag=>tag, :attributes => attributes || default_class.new}) end |
#_text(value, *args) ⇒ Object
Add ‘content’ attribute to existing element.
633 634 635 636 637 |
# File 'lib/rfm/utilities/sax_parser.rb', line 633 def _text(value, *args) #puts "Receiving text '#{value}'" return unless value.to_s[/[^\s]/] @element_buffer[:text] << value end |
#cursor ⇒ Object
562 563 564 |
# File 'lib/rfm/utilities/sax_parser.rb', line 562 def cursor stack.last end |
#dump_cursor ⇒ Object
577 578 579 |
# File 'lib/rfm/utilities/sax_parser.rb', line 577 def dump_cursor stack.pop end |
#element_buffer? ⇒ Boolean
603 604 605 |
# File 'lib/rfm/utilities/sax_parser.rb', line 603 def element_buffer? @element_buffer[:tag] && !@element_buffer[:tag].empty? end |
#get_template(name) ⇒ Object
Takes string, symbol, hash, and returns a (possibly cached) parsing template. String can be a file name, yaml, xml. Symbol is a name of a template stored in SaxParser@templates (you would set the templates when your app or gem loads). Templates stored in the SaxParser@templates var can be strings of code, file specs, or hashes.
532 533 534 535 536 537 538 539 540 541 542 |
# File 'lib/rfm/utilities/sax_parser.rb', line 532 def get_template(name) # dat = templates[name] # if dat # rslt = load_template(dat) # else # rslt = load_template(name) # end # (templates[name] = rslt) #unless dat == rslt # The above works, but this is cleaner. templates[name] = templates[name] && load_template(templates[name]) || load_template(name) end |
#init_element_buffer ⇒ Object
591 592 593 |
# File 'lib/rfm/utilities/sax_parser.rb', line 591 def init_element_buffer @element_buffer = {:tag=>nil, :attributes=>default_class.new, :text=>''} end |
#initialize(_template = nil, initial_object = nil) ⇒ Object
Instance Methods ###
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 |
# File 'lib/rfm/utilities/sax_parser.rb', line 511 def initialize(_template=nil, initial_object=nil) initial_object = case when initial_object.nil?; default_class.new when initial_object.is_a?(Class); initial_object.new when initial_object.is_a?(String) || initial_object.is_a?(Symbol); SaxParser.get_constant(initial_object).new else initial_object end #initial_object = initial_object || default_class.new || {} @stack = [] @template = get_template(_template) @tag_translation = tag_translation #(@template = @template.values[0]) if @template.size == 1 #y @template init_element_buffer set_cursor Cursor.new(@template, initial_object, 'top', self) end |
#load_template(dat) ⇒ Object
Does the heavy-lifting of template retrieval.
545 546 547 548 549 550 551 552 553 554 555 556 |
# File 'lib/rfm/utilities/sax_parser.rb', line 545 def load_template(dat) prefix = defined?(template_prefix) ? template_prefix : '' rslt = case when dat.is_a?(Hash); dat when dat.to_s[/\.y.?ml$/i]; (YAML.load_file(File.join(*[prefix, dat].compact))) # This line might cause an infinite loop. when dat.to_s[/\.xml$/i]; self.class.build(File.join(*[prefix, dat].compact), nil, {'compact'=>true}) when dat.to_s[/^<.*>/i]; "Convert from xml to Hash - under construction" when dat.is_a?(String); YAML.load dat else default_class.new end end |
#result ⇒ Object
558 559 560 |
# File 'lib/rfm/utilities/sax_parser.rb', line 558 def result stack[0].object if stack[0].is_a? Cursor end |
#send_element_buffer ⇒ Object
595 596 597 598 599 600 601 |
# File 'lib/rfm/utilities/sax_parser.rb', line 595 def send_element_buffer if element_buffer? (@element_buffer[:attributes][text_label] = @element_buffer[:text]) if @element_buffer[:text].to_s[/[^\s]/] set_cursor cursor.receive_start_element(@element_buffer[:tag], @element_buffer[:attributes]) init_element_buffer end end |
#set_cursor(args) ⇒ Object
cursor_object
566 567 568 569 570 571 572 573 574 575 |
# File 'lib/rfm/utilities/sax_parser.rb', line 566 def set_cursor(args) # cursor_object if args.is_a? Cursor stack.push(args) cursor.parent = stack[-2] || stack[0] #_stack[0] so methods called on parent won't bomb. # Cursor is no longer storing top or stack, it is delegating those mehthods to main handler. #cursor.top = stack[0] #cursor.stack = stack end cursor end |
#top ⇒ Object
581 582 583 |
# File 'lib/rfm/utilities/sax_parser.rb', line 581 def top stack[0] end |
#transform(name) ⇒ Object
585 586 587 588 589 |
# File 'lib/rfm/utilities/sax_parser.rb', line 585 def transform(name) return name unless @tag_translation.is_a?(Proc) #name.to_s.gsub(*@tag_translation) @tag_translation.call(name.to_s) end |