lib/happymapper/item.rb in happymapper-0.2.0 vs lib/happymapper/item.rb in happymapper-0.2.1

- old
+ new

@@ -5,37 +5,59 @@ Types = [String, Float, Time, Date, DateTime, Integer, Boolean] # options: # :deep => Boolean False to only parse element's children, True to include # grandchildren and all others down the chain (// in expath) + # :namespace => String Element's namespace if it's not the global or inherited + # default + # :parser => Symbol Class method to use for type coercion. + # :raw => Boolean Use raw node value (inc. tags) when parsing. # :single => Boolean False if object should be collection, True for single object + # :tag => String Element name if it doesn't match the specified name. def initialize(name, type, o={}) self.name = name.to_s self.type = type self.tag = o.delete(:tag) || name.to_s - self.options = { - :single => false, - :deep => false, - }.merge(o) + self.options = o @xml_type = self.class.to_s.split('::').last.downcase end - def from_xml_node(node) + def from_xml_node(node, namespace) if primitive? - value_from_xml_node(node) do |value_before_type_cast| - typecast(value_before_type_cast) + find(node, namespace) do |n| + if n.respond_to?(:content) + typecast(n.content) + else + typecast(n.to_s) + end end else - type.parse(node, options) + if options[:parser] + find(node, namespace) do |n| + if n.respond_to?(:content) && !options[:raw] + value = n.content + else + value = n.to_s + end + + begin + type.send(options[:parser].to_sym, value) + rescue + nil + end + end + else + type.parse(node, options) + end end end - def xpath + def xpath(namespace = self.namespace) xpath = '' xpath += './/' if options[:deep] - xpath += namespace if namespace + xpath += "#{namespace}:" if namespace xpath += tag # puts "xpath: #{xpath}" xpath end @@ -84,19 +106,28 @@ value end end private - def value_from_xml_node(node) + def find(node, namespace, &block) + # this node has a custom namespace (that is present in the doc) + if self.namespace && node.namespaces.find_by_prefix(self.namespace) + # from the class definition + namespace = self.namespace + elsif options[:namespace] && node.namespaces.find_by_prefix(options[:namespace]) + # from an element definition + namespace = options[:namespace] + end + if element? - result = node.find_first(xpath) + result = node.find_first(xpath(namespace)) # puts "vfxn: #{xpath} #{result.inspect}" if result - value = yield(result.content) + value = yield(result) if options[:attributes].is_a?(Hash) result.attributes.each do |xml_attribute| if attribute_options = options[:attributes][xml_attribute.name.to_sym] - attribute_value = Attribute.new(xml_attribute.name.to_sym, *attribute_options).from_xml_node(result) + attribute_value = Attribute.new(xml_attribute.name.to_sym, *attribute_options).from_xml_node(result, namespace) result.instance_eval <<-EOV def value.#{xml_attribute.name} #{attribute_value.inspect} end EOV \ No newline at end of file