lib/apricoteatsgorilla.rb in smacks-apricoteatsgorilla-0.4.3 vs lib/apricoteatsgorilla.rb in smacks-apricoteatsgorilla-0.4.4

- old
+ new

@@ -1,6 +1,7 @@ require "rubygems" +require "iconv" require "hpricot" # Apricot eats Gorilla is a SOAP communication helper. # # It translates between SOAP messages (XML) and Ruby Hashes while offering some @@ -28,15 +29,10 @@ attr_accessor :node_namespace # Shortcut method for translating between XML Strings and Ruby Hashes. # Delegates to xml_to_hash in case +source+ is of type String or delegates # to hash_to_xml in case +source+ is of type Hash. Returns nil otherwise. - # - # ==== Parameters - # - # * +source+ - The XML String or Ruby Hash to translate. - # * +root_node+ - Optional. Custom root node to start parsing the given XML. def [](source, root_node = nil) case source when String xml_to_hash(source, root_node) when Hash @@ -56,42 +52,43 @@ # node by default. The optional +root_node+ parameter can be used to specify # a custom root node to start parsing at using an XPath (Hpricot search). # The root node itself won't be included in the Hash. Converts tag names # from CamelCase/lowerCamelCase to snake_case and into Symbols by default. # - # ==== Parameters - # - # * +xml+ - The XML String to translate. - # * +root_node+ - Optional. Custom root node to start parsing the given XML. - # # ==== Examples # # xml = "<apricot><eats>Gorilla</eats></apricot>" # ApricotEatsGorilla[xml] # # => { :eats => "Gorilla" } # # xml = "<apricot><eats><lotsOf>Gorillas</lotsOf></eats></apricot>" # ApricotEatsGorilla[xml, "//eats"] # # => { :lots_of => "Gorillas" } def xml_to_hash(xml, root_node = nil) - doc = Hpricot.XML clean_xml(xml) - root = root_node ? doc.at(root_node) : doc.root + doc = Hpricot.XML remove_whitespace(xml) + root = root_node ? doc.search(root_node) : doc.root - return nil if root.nil? # root_node not found - if root.children.size == 1 && root.children.first.kind_of?(Hpricot::Text) - return root.children.first.to_s # text-only value + return nil if root.nil? + return xml_node_to_hash(root) unless root.respond_to? :each + + if root.size == 1 + return root.first.children.to_s if root.first.children.first.kind_of?(Hpricot::Text) + xml_node_to_hash(root.first) + else + root.map do |node| + if node.children.first.kind_of?(Hpricot::Text) + node.children.to_s + else + xml_node_to_hash(node) + end + end end - xml_node_to_hash(root) end # Converts a given Ruby Hash into an XML String. Converts Hash keys from # snake_case to lowerCamelCase by default. # - # ==== Parameters - # - # * +hash+ - The Ruby Hash to translate. - # # ==== Examples # # hash = { :apricot => { :eats => "Gorilla" } } # ApricotEatsGorilla[hash] # # => "<apricot><eats>Gorilla</eats></apricot>" @@ -105,14 +102,10 @@ # Builds a SOAP request envelope and includes the content from a given +block+ # into the envelope body. Accepts a Hash (namespace => namespace_uri) of # additional +namespaces+ to set. # - # ==== Parameters - # - # * +namespaces+ - A Hash of namespaces and their URI. - # # ==== Examples # # ApricotEatsGorilla.soap_envelope { "<authenticate>me</authenticate>" } # # # => '<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"> @@ -155,22 +148,18 @@ private # Actual implementation for xml_to_hash. Takes and iterates through a given # Hpricot +element+ and returns a Ruby Hash equal to the given content. - # - # ==== Parameters - # - # * +element+ - The Hpricot element to translate. def xml_node_to_hash(element) this_node = {} element.each_child do |child| # hpricot 0.6.1 returns an empty array, while 0.8 returns nil if child.children.nil? || child.children.empty? key, value = child.name, nil elsif child.children.size == 1 && child.children.first.text? - key, value = child.name, to_boolean(child.children.first.to_html) + key, value = child.name, map_to_boolean(child.children.first.to_html) else key, value = child.name, xml_node_to_hash(child) end key = remove_namespace(key) @@ -189,15 +178,10 @@ this_node end # Actual implementation for hash_to_xml. Takes a Hash key +name+ and a # value +item+ and returns an XML String equal to the given content. - # - # ==== Parameters - # - # * +name+ - Root key from Hash to translate. - # * +item+ - Root value from Hash to translate. def nested_data_to_xml(name, item) case item when Array item.map { |subitem| nested_data_to_xml(name, subitem) }.join when Hash @@ -218,46 +202,38 @@ end end # Creates an XML tag. Expects a block for tag content. Defaults to an empty # element tag in case no block was supplied. - # - # ==== Parameters - # - # * +name+ - The name of the XML tag. - # * +attributes+ - Optional. Hash of attributes for the XML tag. def tag(name, attributes = {}) name = to_lower_camel_case(name) unless disable_tag_names_to_lower_camel_case if nodes_to_namespace.kind_of? Array name = "#{node_namespace}:#{name}" if node_namespace && nodes_to_namespace.include?(name) end return "<#{name} />" unless block_given? attr = opt_order(attributes).map { |k, v| %Q( xmlns:#{k}="#{v}") }.to_s - body = (yield && !yield.empty?) ? yield : "" + body = yield || "" "<#{name}#{attr}>" << body << "</#{name}>" end - # Removes line breaks and whitespace between tags from a given +xml+ String. - def clean_xml(xml) - xml.gsub!(/\n+/, "") - xml.gsub!(/(>)\s*(<)/, '\1\2') - xml + # Removes whitespace between tags of a given +xml+ String. + def remove_whitespace(xml) + xml.gsub(/(>)\s*(<)/, '\1\2') end # Removes the namespace from a given XML +tag+. def remove_namespace(tag) - tag.sub!(/.+:(.+)/, '\1') - tag + tag.sub(/.+:(.+)/, '\1') end # Checks to see if a given +string+ matches "true" or "false" and converts # these values to actual Boolean objects. Returns the original String in # case it does not match "true" or "false". - def to_boolean(string) + def map_to_boolean(string) return true if string == "true" return false if string == "false" - string + Iconv.new("iso-8859-1", "utf-8").iconv(string) end # Returns a sorted version of a given +hash+ if sort_keys is enabled. def opt_order(hash) return hash unless sort_keys \ No newline at end of file