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.
622 623 624 |
# File 'lib/rfm/utilities/sax_parser.rb', line 622 def initial_object @initial_object end |
#stack ⇒ Object
Returns the value of attribute stack.
622 623 624 |
# File 'lib/rfm/utilities/sax_parser.rb', line 622 def stack @stack end |
#stack_debug ⇒ Object
Returns the value of attribute stack_debug.
622 623 624 |
# File 'lib/rfm/utilities/sax_parser.rb', line 622 def stack_debug @stack_debug end |
#template ⇒ Object
Returns the value of attribute template.
622 623 624 |
# File 'lib/rfm/utilities/sax_parser.rb', line 622 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)
630 631 632 633 634 635 |
# File 'lib/rfm/utilities/sax_parser.rb', line 630 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.
659 660 661 662 663 664 |
# File 'lib/rfm/utilities/sax_parser.rb', line 659 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.
647 648 649 650 651 652 653 654 655 656 |
# File 'lib/rfm/utilities/sax_parser.rb', line 647 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.
763 764 765 766 767 |
# File 'lib/rfm/utilities/sax_parser.rb', line 763 def _attribute(name, value, *args) #puts "Receiving attribute '#{name}' with value '#{value}'" name = transform name cursor.receive_attribute(name, value) end |
#_doctype(*args) ⇒ Object
789 790 791 792 793 |
# File 'lib/rfm/utilities/sax_parser.rb', line 789 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.
783 784 785 786 787 |
# File 'lib/rfm/utilities/sax_parser.rb', line 783 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.
748 749 750 751 752 753 754 755 756 757 758 759 760 |
# File 'lib/rfm/utilities/sax_parser.rb', line 748 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.
770 771 772 773 774 775 776 777 778 779 780 |
# File 'lib/rfm/utilities/sax_parser.rb', line 770 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
722 723 724 |
# File 'lib/rfm/utilities/sax_parser.rb', line 722 def cursor stack.last end |
#dump_cursor ⇒ Object
734 735 736 |
# File 'lib/rfm/utilities/sax_parser.rb', line 734 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.
687 688 689 690 691 692 693 694 695 696 697 |
# File 'lib/rfm/utilities/sax_parser.rb', line 687 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 ###
670 671 672 673 674 675 676 677 678 679 680 681 |
# File 'lib/rfm/utilities/sax_parser.rb', line 670 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.
700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 |
# File 'lib/rfm/utilities/sax_parser.rb', line 700 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
718 719 720 |
# File 'lib/rfm/utilities/sax_parser.rb', line 718 def result stack[0].object if stack[0].is_a? Cursor end |
#set_cursor(args) ⇒ Object
cursor_object
726 727 728 729 730 731 732 |
# File 'lib/rfm/utilities/sax_parser.rb', line 726 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
738 739 740 |
# File 'lib/rfm/utilities/sax_parser.rb', line 738 def top stack[0] end |
#transform(name) ⇒ Object
742 743 744 745 |
# File 'lib/rfm/utilities/sax_parser.rb', line 742 def transform(name) return name unless TAG_TRANSLATION.is_a?(Proc) TAG_TRANSLATION.call(name.to_s) end |