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.
609 610 611 |
# File 'lib/rfm/utilities/sax_parser.rb', line 609 def initial_object @initial_object end |
#stack ⇒ Object
Returns the value of attribute stack.
609 610 611 |
# File 'lib/rfm/utilities/sax_parser.rb', line 609 def stack @stack end |
#stack_debug ⇒ Object
Returns the value of attribute stack_debug.
609 610 611 |
# File 'lib/rfm/utilities/sax_parser.rb', line 609 def stack_debug @stack_debug end |
#template ⇒ Object
Returns the value of attribute template.
609 610 611 |
# File 'lib/rfm/utilities/sax_parser.rb', line 609 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)
617 618 619 620 621 622 |
# File 'lib/rfm/utilities/sax_parser.rb', line 617 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.
646 647 648 649 650 651 |
# File 'lib/rfm/utilities/sax_parser.rb', line 646 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.
634 635 636 637 638 639 640 641 642 643 |
# File 'lib/rfm/utilities/sax_parser.rb', line 634 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.
746 747 748 749 750 |
# File 'lib/rfm/utilities/sax_parser.rb', line 746 def _attribute(name, value, *args) #puts "Receiving attribute '#{name}' with value '#{value}'" name = transform name cursor.receive_attribute(name, value) end |
#_doctype(*args) ⇒ Object
772 773 774 775 776 |
# File 'lib/rfm/utilities/sax_parser.rb', line 772 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.
766 767 768 769 770 |
# File 'lib/rfm/utilities/sax_parser.rb', line 766 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.
731 732 733 734 735 736 737 738 739 740 741 742 743 |
# File 'lib/rfm/utilities/sax_parser.rb', line 731 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.
753 754 755 756 757 758 759 760 761 762 763 |
# File 'lib/rfm/utilities/sax_parser.rb', line 753 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
705 706 707 |
# File 'lib/rfm/utilities/sax_parser.rb', line 705 def cursor stack.last end |
#dump_cursor ⇒ Object
717 718 719 |
# File 'lib/rfm/utilities/sax_parser.rb', line 717 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.
674 675 676 677 678 679 680 681 682 683 684 |
# File 'lib/rfm/utilities/sax_parser.rb', line 674 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 ###
657 658 659 660 661 662 663 664 665 666 667 668 |
# File 'lib/rfm/utilities/sax_parser.rb', line 657 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.
687 688 689 690 691 692 693 694 695 696 697 698 699 |
# File 'lib/rfm/utilities/sax_parser.rb', line 687 def load_template(dat) prefix = defined?(TEMPLATE_PREFIX) ? TEMPLATE_PREFIX : '' #puts "SaxParser::Handler#load_template... 'prefix' is #{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
701 702 703 |
# File 'lib/rfm/utilities/sax_parser.rb', line 701 def result stack[0].object if stack[0].is_a? Cursor end |
#set_cursor(args) ⇒ Object
cursor_object
709 710 711 712 713 714 715 |
# File 'lib/rfm/utilities/sax_parser.rb', line 709 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
721 722 723 |
# File 'lib/rfm/utilities/sax_parser.rb', line 721 def top stack[0] end |
#transform(name) ⇒ Object
725 726 727 728 |
# File 'lib/rfm/utilities/sax_parser.rb', line 725 def transform(name) return name unless TAG_TRANSLATION.is_a?(Proc) TAG_TRANSLATION.call(name.to_s) end |