lib/happymapper.rb in jnunemaker-happymapper-0.2.0 vs lib/happymapper.rb in jnunemaker-happymapper-0.2.1
- old
+ new
@@ -3,19 +3,21 @@
require 'date'
require 'time'
require 'rubygems'
-gem 'libxml-ruby', '>= 0.9.7'
+gem 'libxml-ruby', '= 0.9.8'
require 'xml'
require 'libxml_ext/libxml_helper'
class Boolean; end
module HappyMapper
-
+
+ DEFAULT_NS = "happymapper"
+
def self.included(base)
base.instance_variable_set("@attributes", {})
base.instance_variable_set("@elements", {})
base.extend ClassMethods
end
@@ -48,73 +50,83 @@
end
def has_many(name, type, options={})
element name, type, {:single => false}.merge(options)
end
-
- # Options:
- # :root => Boolean, true means this is xml root
- def tag(new_tag_name, o={})
- options = {:root => false}.merge(o)
- @root = options.delete(:root)
+
+ # Specify a namespace if a node and all its children are all namespaced
+ # elements. This is simpler than passing the :namespace option to each
+ # defined element.
+ def namespace(namespace = nil)
+ @namespace = namespace if namespace
+ @namespace
+ end
+
+ def tag(new_tag_name)
@tag_name = new_tag_name.to_s
end
def get_tag_name
@tag_name ||= begin
to_s.split('::')[-1].downcase
end
end
- def is_root?
- @root
- end
-
- 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
-
- # puts doc.inspect, doc.respond_to?(:root) ? doc.root.inspect : ''
-
- unless node.namespaces.default.nil?
- namespace = "default_ns:"
- node.namespaces.default_prefix = namespace.chop
- # warn "Default XML namespace present -- results are unpredictable"
+ def parse(xml, options = {})
+ # locally scoped copy of namespace for this parse run
+ namespace = @namespace
+
+ if xml.is_a?(XML::Node)
+ node = xml
+ else
+ if xml.is_a?(XML::Document)
+ node = xml.root
+ else
+ node = xml.to_libxml_doc.root
+ end
+
+ root = node.name == get_tag_name
end
-
- if node.namespaces.to_a.size > 0 && namespace.nil? && !node.namespaces.namespace.nil?
- namespace = node.namespaces.namespace.prefix + ":"
+
+ # This is the entry point into the parsing pipeline, so the default
+ # namespace prefix registered here will propagate down
+ namespaces = node.namespaces
+ if namespaces && namespaces.default
+ namespaces.default_prefix = DEFAULT_NS
+ namespace ||= DEFAULT_NS
end
-
- # xpath += doc.respond_to?(:root) ? '' : '.'
- xpath += is_root? ? '/' : './/'
- xpath += namespace if namespace
+
+ xpath = root ? '/' : './/'
+ xpath += "#{namespace}:" if namespace
xpath += get_tag_name
# puts "parse: #{xpath}"
nodes = node.find(xpath)
- nodes.each do |n|
+ collection = nodes.collect do |n|
obj = new
attributes.each do |attr|
obj.send("#{attr.method_name}=",
- attr.from_xml_node(n))
+ attr.from_xml_node(n, namespace))
end
elements.each do |elem|
- elem.namespace = namespace
obj.send("#{elem.method_name}=",
- elem.from_xml_node(n))
+ elem.from_xml_node(n, namespace))
end
- collection << obj
+
+ obj
end
# per http://libxml.rubyforge.org/rdoc/classes/LibXML/XML/Document.html#M000354
nodes = nil
GC.start
- options[:single] || is_root? ? collection.first : collection
+ if options[:single] || root
+ collection.first
+ else
+ collection
+ end
end
end
end
require 'happymapper/item'