lib/happymapper.rb in jnunemaker-happymapper-0.1.7 vs lib/happymapper.rb in jnunemaker-happymapper-0.2.0

- old
+ new

@@ -23,22 +23,22 @@ module ClassMethods def attribute(name, type, options={}) attribute = Attribute.new(name, type, options) @attributes[to_s] ||= [] @attributes[to_s] << attribute - create_accessor(attribute.name) + attr_accessor attribute.method_name.intern end def attributes @attributes[to_s] || [] end def element(name, type, options={}) element = Element.new(name, type, options) @elements[to_s] ||= [] @elements[to_s] << element - create_accessor(element.name) + attr_accessor element.method_name.intern end def elements @elements[to_s] || [] end @@ -49,93 +49,73 @@ def has_many(name, type, options={}) element name, type, {:single => false}.merge(options) end - def tag(new_tag_name) + # Options: + # :root => Boolean, true means this is xml root + def tag(new_tag_name, o={}) + options = {:root => false}.merge(o) + @root = options.delete(:root) @tag_name = new_tag_name.to_s end def get_tag_name - @tag_name ||= to_s.downcase + @tag_name ||= begin + to_s.split('::')[-1].downcase + end end + + def is_root? + @root + end - def parse(xml, o={}) - options = { - :single => false, - :use_default_namespace => false, - }.merge(o) + def parse(xml, o={}) + xpath, collection, options = '', [], {:single => false}.merge(o) + doc = xml.is_a?(LibXML::XML::Node) ? xml : xml.to_libxml_doc + node = doc.respond_to?(:root) ? doc.root : doc - namespace = "default_ns:" if options[:use_default_namespace] - doc = xml.is_a?(LibXML::XML::Node) ? xml : xml.to_libxml_doc + # puts doc.inspect, doc.respond_to?(:root) ? doc.root.inspect : '' - nodes = if namespace - node = doc.respond_to?(:root) ? doc.root : doc - node.register_default_namespace(namespace.chop) - node.find("#{namespace}#{get_tag_name}") - else - doc.find("//#{get_tag_name}") + unless node.namespaces.default.nil? + namespace = "default_ns:" + node.namespaces.default_prefix = namespace.chop + # warn "Default XML namespace present -- results are unpredictable" end - - nodes = if namespace - node = doc.respond_to?(:root) ? doc.root : doc - node.register_default_namespace(namespace.chop) - node.find("#{namespace}#{get_tag_name}") - else - nested = '.' unless doc.respond_to?(:root) - path = "#{nested}//#{get_tag_name}" - doc.find(path) + + if node.namespaces.to_a.size > 0 && namespace.nil? && !node.namespaces.namespace.nil? + namespace = node.namespaces.namespace.prefix + ":" end - - collection = create_collection(nodes, namespace) - # per http://libxml.rubyforge.org/rdoc/classes/LibXML/XML/Document.html#M000354 - nodes = nil - GC.start + # xpath += doc.respond_to?(:root) ? '' : '.' + xpath += is_root? ? '/' : './/' + xpath += namespace if namespace + xpath += get_tag_name + # puts "parse: #{xpath}" - options[:single] ? collection.first : collection - end - - private - def create_collection(nodes, namespace=nil) - nodes.inject([]) do |acc, el| - obj = new - attributes.each { |attr| obj.send("#{normalize_name attr.name}=", attr.from_xml_node(el)) } - elements.each { |elem| obj.send("#{normalize_name elem.name}=", elem.from_xml_node(el, namespace)) } - acc << obj + nodes = node.find(xpath) + nodes.each do |n| + obj = new + + attributes.each do |attr| + obj.send("#{attr.method_name}=", + attr.from_xml_node(n)) end + + elements.each do |elem| + elem.namespace = namespace + obj.send("#{elem.method_name}=", + elem.from_xml_node(n)) + end + collection << obj end - - def create_getter(name) - name = normalize_name(name) - class_eval <<-EOS, __FILE__, __LINE__ - def #{name} - @#{name} - end - EOS - end + # per http://libxml.rubyforge.org/rdoc/classes/LibXML/XML/Document.html#M000354 + nodes = nil + GC.start - def create_setter(name) - name = normalize_name(name) - - class_eval <<-EOS, __FILE__, __LINE__ - def #{name}=(value) - @#{name} = value - end - EOS - end - - def create_accessor(name) - name = normalize_name(name) - - create_getter(name) - create_setter(name) - end - - def normalize_name(name) - name.gsub('-', '_') - end + options[:single] || is_root? ? collection.first : collection + end end end require 'happymapper/item' require 'happymapper/attribute'