lib/sax-machine/sax_handler.rb in astro-sax-machine-0.0.12.20090419 vs lib/sax-machine/sax_handler.rb in astro-sax-machine-0.0.14

- old
+ new

@@ -1,105 +1,132 @@ require "nokogiri" module SAXMachine class SAXHandler < Nokogiri::XML::SAX::Document attr_reader :object - + def initialize(object) @object = object @parsed_configs = {} end - + def characters(string) if parsing_collection? @collection_handler.characters(string) elsif @element_config @value << string end end - + def cdata_block(string) characters(string) end - + def start_element(name, attrs = []) - @name = name - @attrs = attrs + @name = name + @attrs = attrs.map { |a| SAXHandler.decode_xml(a) } + if parsing_collection? @collection_handler.start_element(@name, @attrs) - + elsif @collection_config = sax_config.collection_config(@name) @collection_handler = @collection_config.handler @collection_handler.start_element(@name, @attrs) - - elsif @element_config = sax_config.element_config_for_attribute(@name, @attrs) - parse_element_attribute - + + elsif (element_configs = sax_config.element_configs_for_attribute(@name, @attrs)).any? + parse_element_attributes(element_configs) + set_element_config_for_element_value + else - @value = "" - @element_config = sax_config.element_config_for_tag(@name, @attrs) + set_element_config_for_element_value end end - + def end_element(name) if parsing_collection? && @collection_config.name == name @object.send(@collection_config.accessor) << @collection_handler.object reset_current_collection - + elsif parsing_collection? @collection_handler.end_element(name) - - elsif characaters_captured? && !parsed_config? + + elsif characaters_captured? mark_as_parsed @object.send(@element_config.setter, @value) end - + reset_current_tag end - + def characaters_captured? !@value.nil? && !@value.empty? end - + def parsing_collection? !@collection_handler.nil? end - - def parse_element_attribute - unless parsed_config? - mark_as_parsed - @element_config.each do |config| - @object.send(config.setter, config.value_from_attrs(@attrs)) + + def parse_collection_instance_attributes + instance = @collection_handler.object + @attrs.each_with_index do |attr_name,index| + instance.send("#{attr_name}=", @attrs[index + 1]) if index % 2 == 0 && instance.methods.include?("#{attr_name}=") + end + end + + def parse_element_attributes(element_configs) + element_configs.each do |ec| + unless parsed_config?(ec) + @object.send(ec.setter, ec.value_from_attrs(@attrs)) + mark_as_parsed(ec) end end - @element_config = nil end - - def mark_as_parsed - # TODO: make this code not suck like this - @parsed_configs[@element_config] = true unless (@element_config.respond_to?(:collection?) && @element_config.collection?) || - (@element_config.class == Array && @element_config.first.collection?) + + def set_element_config_for_element_value + @value = "" + @element_config = sax_config.element_config_for_tag(@name, @attrs) end - - def parsed_config? - @parsed_configs[@element_config] + + def mark_as_parsed(element_config=nil) + element_config ||= @element_config + @parsed_configs[element_config] = true unless element_config.collection? end - + + def parsed_config?(element_config=nil) + element_config ||= @element_config + @parsed_configs[element_config] + end + def reset_current_collection @collection_handler = nil @collection_config = nil end - + def reset_current_tag @name = nil @attrs = nil @value = nil @element_config = nil end - + def sax_config @object.class.sax_config end + + ## + # Decodes XML special characters. + def self.decode_xml(str) + return str.map &method(:decode_xml) if str.kind_of?(Array) + + entities = { + '#38' => '&amp;', + '#13' => "\r", + } + entities.keys.inject(str) { |string, key| + string.gsub(/&#{key};/, entities[key]) + } + end + end end \ No newline at end of file