lib/qbxml/hash.rb in qbxml-0.3.0 vs lib/qbxml/hash.rb in qbxml-0.4.0

- old
+ new

@@ -83,19 +83,27 @@ def self.xml_to_hash(node, hash = {}, opts = {}) node_hash = {CONTENT_ROOT => '', ATTR_ROOT => {}} name = node.name schema = opts[:schema] opts[:typecast_cache] ||= {} + opts[:is_repetitive_cache] ||= {} # Insert node hash into parent hash correctly. case hash[name] when Array hash[name] << node_hash when Hash, String + # This parent has multiple nodes with the same name, but when we checked the first time, + # we found it is not defined as repetitive. I guess this means the schema is a liar. hash[name] = [hash[name], node_hash] else - hash[name] = node_hash + # We didn't see this node name under this parent yet. + if is_repetitive?(schema, node.path, opts[:is_repetitive_cache]) + hash[name] = [node_hash] + else + hash[name] = node_hash + end end # Handle child elements node.children.each do |c| if c.element? @@ -138,9 +146,24 @@ type_path = xpath.gsub(/\[\d+\]/,'') # This is fairly expensive. Cache it for better performance when parsing lots of records of the same type. type_proc = typecast_cache[type_path] ||= Qbxml::TYPE_MAP[schema.xpath(type_path).first.try(:text)] raise "#{xpath} is not a valid type" unless type_proc type_proc[value] + end + + # Determines if the node is repetitive. Just because something is repetitive doesn't mean it always repeats. + # For example, a customer query could return 1 result or 100, but in both cases, we should be returning an + # Array. + def self.is_repetitive?(schema, xpath, is_repetitive_cache) + # Yes, we are parsing comments. + comment_path = xpath.gsub(/\[\d+\]/,'') + "/comment()" + return is_repetitive_cache[comment_path] || parse_repetitive_from_comment(schema, comment_path) + end + + def self.parse_repetitive_from_comment(schema, comment_path) + comment = schema.xpath(comment_path).first + return false if comment.nil? + return comment.text.include?('may rep') end def self.deep_convert(hash, opts = {}, &block) hash.inject(self.new) do |h, (k,v)| k = k.to_s