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
-
#initial_object ⇒ Object
Returns the value of attribute initial_object.
-
#stack ⇒ Object
Returns the value of attribute stack.
-
#stack_debug ⇒ Object
Returns the value of attribute stack_debug.
-
#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
-
#get_template(name) ⇒ Object
Takes string, symbol, hash, and returns a (possibly cached) parsing template.
-
#initialize(_template = nil, _initial_object = nil) ⇒ Object
Instance Methods ###.
-
#load_template(dat) ⇒ Object
Does the heavy-lifting of template retrieval.
- #result ⇒ Object
-
#set_cursor(args) ⇒ Object
cursor_object.
- #top ⇒ Object
- #transform(name) ⇒ Object
Instance Attribute Details
#initial_object ⇒ Object
Returns the value of attribute initial_object.
615 616 617 |
# File 'lib/rfm/utilities/sax_parser.rb', line 615 def initial_object @initial_object end |
#stack ⇒ Object
Returns the value of attribute stack.
615 616 617 |
# File 'lib/rfm/utilities/sax_parser.rb', line 615 def stack @stack end |
#stack_debug ⇒ Object
Returns the value of attribute stack_debug.
615 616 617 |
# File 'lib/rfm/utilities/sax_parser.rb', line 615 def stack_debug @stack_debug end |
#template ⇒ Object
Returns the value of attribute template.
615 616 617 |
# File 'lib/rfm/utilities/sax_parser.rb', line 615 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)
623 624 625 626 627 628 |
# File 'lib/rfm/utilities/sax_parser.rb', line 623 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.
652 653 654 655 656 657 |
# File 'lib/rfm/utilities/sax_parser.rb', line 652 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.
640 641 642 643 644 645 646 647 648 649 |
# File 'lib/rfm/utilities/sax_parser.rb', line 640 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.
756 757 758 759 760 |
# File 'lib/rfm/utilities/sax_parser.rb', line 756 def _attribute(name, value, *args) #puts "Receiving attribute '#{name}' with value '#{value}'" name = transform name cursor.receive_attribute(name, value) end |
#_doctype(*args) ⇒ Object
782 783 784 785 786 |
# File 'lib/rfm/utilities/sax_parser.rb', line 782 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.
776 777 778 779 780 |
# File 'lib/rfm/utilities/sax_parser.rb', line 776 def _end_element(tag, *args) tag = transform tag #puts "Receiving end_element '#{tag}'" cursor.receive_end_element(tag) and dump_cursor end |
#_start_element(tag, attributes = nil, *args) ⇒ Object
Add a node to an existing element.
741 742 743 744 745 746 747 748 749 750 751 752 753 |
# File 'lib/rfm/utilities/sax_parser.rb', line 741 def _start_element(tag, attributes=nil, *args) #puts ["_START_ELEMENT", tag, attributes, args].to_yaml # if tag.to_s.downcase=='fmrestulset' tag = transform tag 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 set_cursor cursor.receive_start_element(tag, attributes) end |
#_text(value, *args) ⇒ Object
Add ‘content’ attribute to existing element.
763 764 765 766 767 768 769 770 771 772 773 |
# File 'lib/rfm/utilities/sax_parser.rb', line 763 def _text(value, *args) #puts "Receiving text '#{value}'" #puts RUBY_VERSION_NUM if RUBY_VERSION_NUM > 1.8 && value.is_a?(String) #puts "Forcing utf-8" value.force_encoding('UTF-8') end # I think the reason this was here is no longer relevant, so I'm disabeling. return unless value[/[^\s]/] cursor.receive_attribute(TEXT_LABEL, value) end |
#cursor ⇒ Object
715 716 717 |
# File 'lib/rfm/utilities/sax_parser.rb', line 715 def cursor stack.last end |
#dump_cursor ⇒ Object
727 728 729 |
# File 'lib/rfm/utilities/sax_parser.rb', line 727 def dump_cursor stack.pop 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.
680 681 682 683 684 685 686 687 688 689 690 |
# File 'lib/rfm/utilities/sax_parser.rb', line 680 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 |
#initialize(_template = nil, _initial_object = nil) ⇒ Object
Instance Methods ###
663 664 665 666 667 668 669 670 671 672 673 674 |
# File 'lib/rfm/utilities/sax_parser.rb', line 663 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 @stack = [] @stack_debug=[] @template = get_template(_template) set_cursor Cursor.new('__TOP__', self).process_new_element end |
#load_template(dat) ⇒ Object
Does the heavy-lifting of template retrieval.
693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 |
# File 'lib/rfm/utilities/sax_parser.rb', line 693 def load_template(dat) #puts "DAT: #{dat}, class #{dat.class}" prefix = defined?(TEMPLATE_PREFIX) ? TEMPLATE_PREFIX : '' #puts "SaxParser::Handler#load_template... 'prefix' is #{prefix}" rslt = case when dat.is_a?(Hash); dat when (dat.is_a?(String) && dat[/^\//]); YAML.load_file 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 #puts rslt rslt end |
#result ⇒ Object
711 712 713 |
# File 'lib/rfm/utilities/sax_parser.rb', line 711 def result stack[0].object if stack[0].is_a? Cursor end |
#set_cursor(args) ⇒ Object
cursor_object
719 720 721 722 723 724 725 |
# File 'lib/rfm/utilities/sax_parser.rb', line 719 def set_cursor(args) # cursor_object if args.is_a? Cursor stack.push(args) #@stack_debug.push(args.dup.tap(){|c| c.handler = c.handler.object_id; c.parent = c.parent.tag}) end cursor end |
#top ⇒ Object
731 732 733 |
# File 'lib/rfm/utilities/sax_parser.rb', line 731 def top stack[0] end |
#transform(name) ⇒ Object
735 736 737 738 |
# File 'lib/rfm/utilities/sax_parser.rb', line 735 def transform(name) return name unless TAG_TRANSLATION.is_a?(Proc) TAG_TRANSLATION.call(name.to_s) end |