I need to parse some XML-RPC-formatted XML in Ruby. I don't have access to the XML-RPC service, I just want to turn an XML string that is returned from such a service into the respective Ruby objects (hashes, arrays, strings etc).
I've played around with the built-in XMLRPC stuff (in Ruby 1.9.3), but I don't get very far:
require 'xmlrpc/parser'
parser = XMLRPC::XMLParser::XMLParser.new
That results in this exception:
LoadError: cannot load such file -- xmltreebuilder
from /Users/johannes/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from /Users/johannes/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from /Users/johannes/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/1.9.1/xmlrpc/parser.rb:620:in `initialize'
from (irb):2:in `new'
from (irb):2
from /Users/johannes/.rvm/rubies/ruby-1.9.3-p0/bin/irb:16:in `<main>'
I then tried to instantiate different XMLParser subclasses, all to no avail.
Do you have any pointers on how to get this to work? Is it even possible to just parse RPC XML without using the XMLRPC::Client with the built-in library?
Thanks!
Update:
This works, but it is oh-so-very-ugly. This just can't be right:
require 'xmlrpc/client'
require "rexml/document"
xml = %{<answer>
<value>
<struct>
<member><name>test</name><value><string>hello</string></value></member>
<member><name>age</name><value><i4>12</i4></value></member>
<member>
<name>requirements</name>
<value>
<struct>
<member>
<name>confirmation</name>
<value>
<array>
<data>
<value><string>Bread</string></value>
<value><string>Butter</string></value>
</data>
</array>
</value>
</member>
<member>
<name>document</name>
<value>
<array>
<data>
<value><string>Tic</string></value>
<value><string>Tac</string></value>
<value><string>Toe</string></value>
</data>
</array>
</value>
</member>
</struct>
</value>
</member>
<member><name>width</name><value><i4>10</i4></value></member>
<member><name>height</name><value><i4>2</i4></value></member>
</struct>
</value>
</answer>}
parser = XMLRPC::XMLParser::REXMLStreamParser::StreamListener.new
parser.parse(xml)
puts "Value (accessor): '#{parser.value}'"
puts "Values (accessor): '#{parser.values}'"
puts "Value (instance_variable_get): '#{parser.instance_variable_get('@value')}'"
There must be a better way!
This is the output:
Value (accessor): ''
Values (accessor): ''
Value (instance_variable_get): '{"test"=>"hello", "age"=>12, "requirements"=>{"confirmation"=>["Bread", "Butter"], "document"=>["Tic", "Tac", "Toe"]}, "width"=>10, "height"=>2}'
This makes my eyes hurt.
This is the closest thing to a solution I could find:
This works, but it is oh-so-very-ugly. This just can't be right:
require 'xmlrpc/client'
require "rexml/document"
xml = %{<answer>
<value>
<struct>
<member><name>test</name><value><string>hello</string></value></member>
<member><name>age</name><value><i4>12</i4></value></member>
<member>
<name>requirements</name>
<value>
<struct>
<member>
<name>confirmation</name>
<value>
<array>
<data>
<value><string>Bread</string></value>
<value><string>Butter</string></value>
</data>
</array>
</value>
</member>
<member>
<name>document</name>
<value>
<array>
<data>
<value><string>Tic</string></value>
<value><string>Tac</string></value>
<value><string>Toe</string></value>
</data>
</array>
</value>
</member>
</struct>
</value>
</member>
<member><name>width</name><value><i4>10</i4></value></member>
<member><name>height</name><value><i4>2</i4></value></member>
</struct>
</value>
</answer>}
parser = XMLRPC::XMLParser::REXMLStreamParser::StreamListener.new
parser.parse(xml)
puts "Value (accessor): '#{parser.value}'"
puts "Values (accessor): '#{parser.values}'"
puts "Value (instance_variable_get): '#{parser.instance_variable_get('@value')}'"
There must be a better way!
This is the output:
Value (accessor): ''
Values (accessor): ''
Value (instance_variable_get): '{"test"=>"hello", "age"=>12, "requirements"=>{"confirmation"=>["Bread", "Butter"], "document"=>["Tic", "Tac", "Toe"]}, "width"=>10, "height"=>2}'
This makes my eyes hurt.