【问题标题】:How to parse XML-RPC-formatted XML in Ruby?如何在 Ruby 中解析 XML-RPC 格式的 XML?
【发布时间】:2012-10-10 06:29:41
【问题描述】:

我需要在 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}'

这让我的眼睛很痛。

【问题讨论】:

    标签: ruby xml xml-parsing xml-rpc


    【解决方案1】:

    这个问题可能已经过时了,但它仍然是谷歌搜索“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]]
    

    【讨论】:

      【解决方案2】:

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

      这行得通,但它太丑了。这是不可能的:

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

      这让我的眼睛很痛。

      【讨论】:

        【解决方案3】:

        与@mfojtik 一样,我打算推荐Nokogiri,因为它是一个出色的XML 解析器,但我通过谷歌搜索发现了Rapuncel。它是一个基于 Nokogiri 的 XML-RPC 客户端,专门用于发送/接收 XML-RPC 并对其进行解析。

        不确定它是否已被维护,但可能值得一试。如果不是,您可以随时使用 Nokogiri 作为基础编写自己的代码,因为它看起来不太复杂。

        【讨论】:

          【解决方案4】:

          检查“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
          

          等等

          【讨论】:

          • 谢谢,我已经广泛使用了 Nokogiri,而且我确实使用 Nokogiri 编写了自己的 XML-RPC 解析器。不过,我不想重新发明轮子。这就是为什么我想了解如何使用现有的解决方案来解析 XML-RPC。
          【解决方案5】:

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

          【讨论】:

          • 谢谢,我试过了。唯一没有抛出异常的是REXMLStreamParser,即使那个也没有按预期工作(请参阅更新的问题)。
          猜你喜欢
          • 2011-10-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-25
          • 2010-10-29
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多