34d2ae3f7fdcec853ec24cf85715da96

With ruby you could use REXML's Hash.from_xml, but I really don't like that. The reason for me to write this, was to convert various xml responses from different soap services to a hash. I don't want any namespaces, attributes, etc. Here's an example response:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:authenticateResponse xmlns:ns2="http://v1_0.ws.some.namespace/">
<return>
<authenticationValue>
<orderToken>dfgdfg-4356345-sdfsdf-2345234-234</orderToken>
<tokenHash>000111DDD888444777NNNZZZ555000</tokenHash>
<client>dude</client>
</authenticationValue>
<success>true</success>
</return>
</ns2:authenticateResponse>
</soap:Body>
</soap:Envelope>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
require 'hpricot'

class Parser

  def self.soap_response_to_hash(xml)
    xml.gsub!(/\n+/, "")
    xml.gsub!(/(>)\s*(<)/, '\1\2')
    doc = Hpricot.XML(xml)
    return xml_node_to_hash doc.at("//return")
  end

private

  def self.xml_node_to_hash(node)
    this_node = {}

    node.each_child do |child|
      if child.children.nil?
        key, value = child.name, nil
      elsif child.children.size == 1 && child.children.first.text?
        key, value = child.name, rubylize(child.children.first.raw_string)
      else
        key, value = child.name, xml_node_to_hash(child)
      end

      current = this_node[key]
      case current
        when Array:
          this_node[key] << value
        when nil
          this_node[key] = value
        else
          this_node[key] = [current.dup, value]
      end
    end

    return this_node
  end

  def self.rubylize(string)
    case string
      when "true":
        true
      when "false":
        false
      else
        string
    end
  end

end

result = Parser::soap_response_to_hash(xml)

Refactorings

No refactoring yet !

Avatar

kotrin

August 8, 2009, August 08, 2009 05:49, permalink

No rating. Login to rate!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
require 'rubygems'
require 'hpricot'

class Parse
  def self.to_hash n
    h = {}
    n.each_child do |c|
      c.respond_to?(:children) ?
        h[c.name] = c.children.size>1 ? to_hash(c) : c.children[0].name :
        h[n.name] = c.name
    end
    h
  end
end

doc = Hpricot.XML xml.gsub(/(>)\s*(<)/, '\1\2').gsub(/\n+/, "")
node = doc%'//return'
hash = Parse.to_hash node

Your refactoring





Format Copy from initial code

or Cancel