如何在Ruby中解析XML-RPC格式的XML?

时间:2012-10-19 15:35:44

标签: ruby xml xml-parsing xml-rpc

我需要在Ruby中解析一些XML-RPC格式的XML。我无法访问XML-RPC服务,我只想将从这样的服务返回的XML字符串转换为相应的Ruby对象(哈希,数组,字符串等)。

我已经使用了内置的XMLRPC内容(在Ruby 1.9.3中),但我没有走得太远:

require 'xmlrpc/parser'
parser = XMLRPC::XMLParser::XMLParser.new

导致此异常:

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>'

然后我尝试实例化不同的XMLParser子类,但都无济于事。

您对如何使其发挥作用有任何指示吗?甚至可以在不使用带内置库的XMLRPC :: Client的情况下解析RPC XML吗?

谢谢!

更新

这样可行,但它非常难看。这不可能是正确的:

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')}'"

必须有更好的方法!

这是输出:

Value (accessor): ''
Values (accessor): ''
Value (instance_variable_get): '{"test"=>"hello", "age"=>12, "requirements"=>{"confirmation"=>["Bread", "Butter"], "document"=>["Tic", "Tac", "Toe"]}, "width"=>10, "height"=>2}'

这让我的眼睛受伤了。

5 个答案:

答案 0 :(得分:1)

检查'nokogiri'宝石:

irb> require 'nokogiri'
irb> doc = Nokogiri::XML('<root><a>test</a></root>')
irb> puts (doc/'root/a').first.text # => 'test'

irb> puts doc.xpath('doc/root/a').first.text

答案 1 :(得分:0)

xmlrpc 库显然有多个解析器,默认为XMLTreeParser,需要库 xmltreebuilder (我不知道,哪个很明显不属于标准的lib)。 但也许你可以尝试另一种解析器?使用XMLRPC::XMLParser.each_installed_parser {|p| puts p.class},您将获得所有(可实例化的)解析器的列表。所以你可能会让其他人正常工作......

答案 2 :(得分:0)

与@mfojtik一样,我打算建议Nokogiri,因为它是一个优秀的XML解析器,但我通过谷歌搜索了Rapuncel。它是一个基于Nokogiri的XML-RPC客户端,专门用于发送/接收XML-RPC并解析它。

不确定它是否已经维护,但可能值得一试。如果不是,你总是可以用Nokogiri作为基础编写自己的,因为它看起来并不太复杂。

答案 3 :(得分:0)

这是我能找到的解决方案最接近的事情:

这样可行,但它非常难看。这不可能是正确的:

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')}'"

必须有更好的方法!

这是输出:

Value (accessor): ''
Values (accessor): ''
Value (instance_variable_get): '{"test"=>"hello", "age"=>12, "requirements"=>{"confirmation"=>["Bread", "Butter"], "document"=>["Tic", "Tac", "Toe"]}, "width"=>10, "height"=>2}'

这让我的眼睛受伤了。

答案 4 :(得分:0)

这个问题可能已经过时,但是在搜索“ ruby​​ parse xml rpc”时仍然是热门话题。

使用XMLRPC::Marshal

可以更轻松地解析ruby XMLRPC字符串。
require 'xmlrpc/marshal'

def parse_xml_rpc(xml_string)
  parser = XMLRPC::Marshal.new
  parser.load_call(xml_string)
end

上面的函数返回一个元组,该元组首先包含该函数的名称,然后包含一个传递的参数数组。

str = "<?xml version=\"1.0\" ?><methodCall><methodName>function_name</methodName><params><param><value><string>arg1</string></value></param><param><value><boolean>1</boolean></value></param><param><value><double>27.5</double></value></param></params></methodCall>\n"

parse_xml_rpc(str)
=> ["function_name", ["arg1", true, 27.5]]