diff --git a/lib/qbxml/hash.rb b/lib/qbxml/hash.rb index 0b47427..89ecf0a 100644 --- a/lib/qbxml/hash.rb +++ b/lib/qbxml/hash.rb @@ -85,15 +85,23 @@ def self.xml_to_hash(node, hash = {}, opts = {}) 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 @@ -142,6 +150,21 @@ def self.typecast(schema, xpath, value, typecast_cache) 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 diff --git a/test/unit/xml_to_hash_test.rb b/test/unit/xml_to_hash_test.rb index 1828438..7dbdbad 100644 --- a/test/unit/xml_to_hash_test.rb +++ b/test/unit/xml_to_hash_test.rb @@ -26,9 +26,28 @@ def test_array_of_strings assert_equal h, qbxml.from_qbxml("\n\n \n \n TxnID\n RefNumber\n \n \n\n") end - def test_float_percentage + def test_array_with_one_element qbxml = Qbxml.new + h = { + "qbxml" => { + "xml_attributes" => {}, + "qbxml_msgs_rs" => { + "xml_attributes" => {}, + 'customer_query_rs' => { + "xml_attributes" => {}, + 'customer_ret' => [{ + "xml_attributes"=> {}, + 'list_id' => 'abc' + }] + } + } + } + } + assert_equal h, qbxml.from_qbxml("\n\n \n \n abc\n \n \n\n") + end + def test_float_percentage + qbxml = Qbxml.new h = { "qbxml" => { "xml_attributes" => {},