如何解析来自 ruby​​ 客户端的 SOAP 响应?

发布于 2024-08-19 15:36:31 字数 2136 浏览 3 评论 0原文

我正在学习 Ruby,我编写了以下代码来了解如何使用 SOAP 服务:

require 'soap/wsdlDriver'
wsdl="http://www.abundanttech.com/webservices/deadoralive/deadoralive.wsdl"
service=SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver
weather=service.getTodaysBirthdays('1/26/2010')

我得到的响应是:

#<SOAP::Mapping::Object:0x80ac3714 
{http://www.abundanttech.com/webservices/deadoralive} getTodaysBirthdaysResult=#<SOAP::Mapping::Object:0x80ac34a8 
{http://www.w3.org/2001/XMLSchema}schema=#<SOAP::Mapping::Object:0x80ac3214 
{http://www.w3.org/2001/XMLSchema}element=#<SOAP::Mapping::Object:0x80ac2f6c 
{http://www.w3.org/2001/XMLSchema}complexType=#<SOAP::Mapping::Object:0x80ac2cc4 
{http://www.w3.org/2001/XMLSchema}choice=#<SOAP::Mapping::Object:0x80ac2a1c 
{http://www.w3.org/2001/XMLSchema}element=#<SOAP::Mapping::Object:0x80ac2774 
{http://www.w3.org/2001/XMLSchema}complexType=#<SOAP::Mapping::Object:0x80ac24cc 
{http://www.w3.org/2001/XMLSchema}sequence=#<SOAP::Mapping::Object:0x80ac2224 
{http://www.w3.org/2001/XMLSchema}element=[#<SOAP::Mapping::Object:0x80ac1f7c>, 
#<SOAP::Mapping::Object:0x80ac13ec>, 
#<SOAP::Mapping::Object:0x80ac0a28>, 
#<SOAP::Mapping::Object:0x80ac0078>, 
#<SOAP::Mapping::Object:0x80abf6c8>, 
#<SOAP::Mapping::Object:0x80abed18>]
>>>>>>> {urn:schemas-microsoft-com:xml-diffgram-v1}diffgram=#<SOAP::Mapping::Object:0x80abe6c4 
{}NewDataSet=#<SOAP::Mapping::Object:0x80ac1220 
{}Table=[#<SOAP::Mapping::Object:0x80ac75e4 
{}FullName="Cully,  Zara" 
{}BirthDate="01/26/1892" 
{}DeathDate="02/28/1979" 
{}Age="(87)" 
{}KnownFor="The Jeffersons" 
{}DeadOrAlive="Dead">, 
#<SOAP::Mapping::Object:0x80b778f4 
{}FullName="Feiffer, Jules" 
{}BirthDate="01/26/1929" 
{}DeathDate=#<SOAP::Mapping::Object:0x80c7eaf4> 
{}Age="81" 
{}KnownFor="Cartoonists" 
{}DeadOrAlive="Alive">]>>>>

我很难弄清楚如何解析并在一个漂亮的表中显示返回的信息,甚至只是如何循环记录并访问每个元素(即全名、年龄等)。我浏览了整个“getTodaysBirthdaysResult.methods - Object.new.methods”,并继续努力尝试找出如何访问元素,但后来我到达数组时却迷路了。

任何可以提供的帮助将不胜感激。

I am learning Ruby and I have written the following code to find out how to consume SOAP services:

require 'soap/wsdlDriver'
wsdl="http://www.abundanttech.com/webservices/deadoralive/deadoralive.wsdl"
service=SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver
weather=service.getTodaysBirthdays('1/26/2010')

The response that I get back is:

#<SOAP::Mapping::Object:0x80ac3714 
{http://www.abundanttech.com/webservices/deadoralive} getTodaysBirthdaysResult=#<SOAP::Mapping::Object:0x80ac34a8 
{http://www.w3.org/2001/XMLSchema}schema=#<SOAP::Mapping::Object:0x80ac3214 
{http://www.w3.org/2001/XMLSchema}element=#<SOAP::Mapping::Object:0x80ac2f6c 
{http://www.w3.org/2001/XMLSchema}complexType=#<SOAP::Mapping::Object:0x80ac2cc4 
{http://www.w3.org/2001/XMLSchema}choice=#<SOAP::Mapping::Object:0x80ac2a1c 
{http://www.w3.org/2001/XMLSchema}element=#<SOAP::Mapping::Object:0x80ac2774 
{http://www.w3.org/2001/XMLSchema}complexType=#<SOAP::Mapping::Object:0x80ac24cc 
{http://www.w3.org/2001/XMLSchema}sequence=#<SOAP::Mapping::Object:0x80ac2224 
{http://www.w3.org/2001/XMLSchema}element=[#<SOAP::Mapping::Object:0x80ac1f7c>, 
#<SOAP::Mapping::Object:0x80ac13ec>, 
#<SOAP::Mapping::Object:0x80ac0a28>, 
#<SOAP::Mapping::Object:0x80ac0078>, 
#<SOAP::Mapping::Object:0x80abf6c8>, 
#<SOAP::Mapping::Object:0x80abed18>]
>>>>>>> {urn:schemas-microsoft-com:xml-diffgram-v1}diffgram=#<SOAP::Mapping::Object:0x80abe6c4 
{}NewDataSet=#<SOAP::Mapping::Object:0x80ac1220 
{}Table=[#<SOAP::Mapping::Object:0x80ac75e4 
{}FullName="Cully,  Zara" 
{}BirthDate="01/26/1892" 
{}DeathDate="02/28/1979" 
{}Age="(87)" 
{}KnownFor="The Jeffersons" 
{}DeadOrAlive="Dead">, 
#<SOAP::Mapping::Object:0x80b778f4 
{}FullName="Feiffer, Jules" 
{}BirthDate="01/26/1929" 
{}DeathDate=#<SOAP::Mapping::Object:0x80c7eaf4> 
{}Age="81" 
{}KnownFor="Cartoonists" 
{}DeadOrAlive="Alive">]>>>>

I am having a great deal of difficulty figuring out how to parse and show the returned information in a nice table, or even just how to loop through the records and have access to each element (ie. FullName,Age,etc). I went through the whole "getTodaysBirthdaysResult.methods - Object.new.methods" and kept working down to try and work out how to access the elements, but then I get to the array and I got lost.

Any help that can be offered would be appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

绿萝 2024-08-26 15:36:31

如果您无论如何都要解析 XML,您不妨跳过 SOAP4r 并使用 Handsoap。免责声明:我是 Handsoap 的作者之一。

示例实现:

# wsdl: http://www.abundanttech.com/webservices/deadoralive/deadoralive.wsdl
DEADORALIVE_SERVICE_ENDPOINT = {
  :uri => 'http://www.abundanttech.com/WebServices/DeadOrAlive/DeadOrAlive.asmx',
  :version => 1
}

class DeadoraliveService < Handsoap::Service
  endpoint DEADORALIVE_SERVICE_ENDPOINT
  def on_create_document(doc)
    # register namespaces for the request
    doc.alias 'tns', 'http://www.abundanttech.com/webservices/deadoralive'
  end

  def on_response_document(doc)
    # register namespaces for the response
    doc.add_namespace 'ns', 'http://www.abundanttech.com/webservices/deadoralive'
  end

  # public methods

  def get_todays_birthdays
    soap_action = 'http://www.abundanttech.com/webservices/deadoralive/getTodaysBirthdays'
    response = invoke('tns:getTodaysBirthdays', soap_action)
    (response/"//NewDataSet/Table").map do |table|
      {
        :full_name => (table/"FullName").to_s,
        :birth_date => Date.strptime((table/"BirthDate").to_s, "%m/%d/%Y"),
        :death_date => Date.strptime((table/"DeathDate").to_s, "%m/%d/%Y"),
        :age => (table/"Age").to_s.gsub(/^\(([\d]+)\)$/, '\1').to_i,
        :known_for => (table/"KnownFor").to_s,
        :alive? => (table/"DeadOrAlive").to_s == "Alive"
      }
    end
  end
end

用法:

DeadoraliveService.get_todays_birthdays

If you're going to parse the XML anyway, you might as well skip SOAP4r and go with Handsoap. Disclaimer: I'm one of the authors of Handsoap.

An example implementation:

# wsdl: http://www.abundanttech.com/webservices/deadoralive/deadoralive.wsdl
DEADORALIVE_SERVICE_ENDPOINT = {
  :uri => 'http://www.abundanttech.com/WebServices/DeadOrAlive/DeadOrAlive.asmx',
  :version => 1
}

class DeadoraliveService < Handsoap::Service
  endpoint DEADORALIVE_SERVICE_ENDPOINT
  def on_create_document(doc)
    # register namespaces for the request
    doc.alias 'tns', 'http://www.abundanttech.com/webservices/deadoralive'
  end

  def on_response_document(doc)
    # register namespaces for the response
    doc.add_namespace 'ns', 'http://www.abundanttech.com/webservices/deadoralive'
  end

  # public methods

  def get_todays_birthdays
    soap_action = 'http://www.abundanttech.com/webservices/deadoralive/getTodaysBirthdays'
    response = invoke('tns:getTodaysBirthdays', soap_action)
    (response/"//NewDataSet/Table").map do |table|
      {
        :full_name => (table/"FullName").to_s,
        :birth_date => Date.strptime((table/"BirthDate").to_s, "%m/%d/%Y"),
        :death_date => Date.strptime((table/"DeathDate").to_s, "%m/%d/%Y"),
        :age => (table/"Age").to_s.gsub(/^\(([\d]+)\)$/, '\1').to_i,
        :known_for => (table/"KnownFor").to_s,
        :alive? => (table/"DeadOrAlive").to_s == "Alive"
      }
    end
  end
end

Usage:

DeadoraliveService.get_todays_birthdays
∞梦里开花 2024-08-26 15:36:31

SOAP4R 总是返回一个 SOAP::Mapping::Object ,有时使用起来有点困难,除非您只是获取可以使用散列表示法访问的散列值,如下所示

weather['fullName']

但是,当您有散列数组时,它不起作用。解决方法是获取 xml 格式的结果,而不是 SOAP::Mapping::Object。为此,我将修改您的代码,

 require 'soap/wsdlDriver'
 wsdl="http://www.abundanttech.com/webservices/deadoralive/deadoralive.wsdl"
 service=SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver
 service.return_response_as_xml = true
 weather=service.getTodaysBirthdays('1/26/2010')

现在上面将为您提供一个 xml 响应,您可以使用 nokogiri 或 REXML 对其进行解析。这是使用 REXML 的示例,

  require 'rexml/document'
  rexml = REXML::Document.new(weather)
  birthdays = nil
  rexml.each_recursive {|element| birthdays = element if element.name == 'getTodaysBirthdaysResult'}
  birthdays.each_recursive{|element| puts "#{element.name} = #{element.text}" if element.text}

这将打印出包含任何文本的所有元素。

因此,一旦您创建了 xml 文档,您几乎可以根据您选择的库所具有的方法执行任何操作,即。 REXML 或 Nokogiri

SOAP4R always returns a SOAP::Mapping::Object which is sometimes a bit difficult to work with unless you are just getting the hash values that you can access using hash notation like so

weather['fullName']

However, it does not work when you have an array of hashes. A work around is to get the result in xml format instead of SOAP::Mapping::Object. To do that I will modify your code as

 require 'soap/wsdlDriver'
 wsdl="http://www.abundanttech.com/webservices/deadoralive/deadoralive.wsdl"
 service=SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver
 service.return_response_as_xml = true
 weather=service.getTodaysBirthdays('1/26/2010')

Now the above would give you an xml response which you can parse using nokogiri or REXML. Here is the example using REXML

  require 'rexml/document'
  rexml = REXML::Document.new(weather)
  birthdays = nil
  rexml.each_recursive {|element| birthdays = element if element.name == 'getTodaysBirthdaysResult'}
  birthdays.each_recursive{|element| puts "#{element.name} = #{element.text}" if element.text}

This will print out all elements that have any text.

So once you have created an xml document you can pretty much do anything depending upon the methods the library you choose has ie. REXML or Nokogiri

挽清梦 2024-08-26 15:36:31

嗯,这是我的建议。

问题是,你必须抓住结果的正确部分,这是你实际上可以迭代的部分。不幸的是,世界上所有的检查都无法帮助你,因为它是一大堆不可读的文本。

我所做的是:

File.open('myresult.yaml', 'w') {|f| f.write(result.to_yaml) }

这将是一种更易于人类阅读的格式。您可能正在寻找的是这样的内容:

    --- !ruby/object:SOAP::Mapping::Object 


    __xmlattr: {}

      __xmlele: 

  - - &id024 !ruby/object:XSD::QName 
      name: ListAddressBooksResult <-- Hash name, so it's resul["ListAddressBooksResult"]
      namespace: http://apiconnector.com
      source: 
    - !ruby/object:SOAP::Mapping::Object 
      __xmlattr: {}

      __xmlele: 
      - - &id023 !ruby/object:XSD::QName 
          name: APIAddressBook <-- this bastard is enumerable :) YAY! so it's result["ListAddressBooksResult"]["APIAddressBook"].each
          namespace: http://apiconnector.com
          source: 
        - - !ruby/object:SOAP::Mapping::Object

上面是 DotMailer 的 API 的结果,我花了最后一个小时试图弄清楚如何枚举结果。以上是我用来弄清楚到底发生了什么的技术。我认为这样比使用 REXML 等更好,我可以做这样的事情:

result['ListAddressBooksResult']['APIAddressBook'].each {|book| puts book["Name"]}

嗯,我希望这可以帮助其他正在寻找的人。

/杰森

Well, Here's my suggestion.

The issue is, you have to snag the right part of the result, one that is something you can actually iterator over. Unfortunately, all the inspecting in the world won't help you because it's a huge blob of unreadable text.

What I do is this:

File.open('myresult.yaml', 'w') {|f| f.write(result.to_yaml) }

This will be a much more human readable format. What you are probably looking for is something like this:

    --- !ruby/object:SOAP::Mapping::Object 


    __xmlattr: {}

      __xmlele: 

  - - &id024 !ruby/object:XSD::QName 
      name: ListAddressBooksResult <-- Hash name, so it's resul["ListAddressBooksResult"]
      namespace: http://apiconnector.com
      source: 
    - !ruby/object:SOAP::Mapping::Object 
      __xmlattr: {}

      __xmlele: 
      - - &id023 !ruby/object:XSD::QName 
          name: APIAddressBook <-- this bastard is enumerable :) YAY! so it's result["ListAddressBooksResult"]["APIAddressBook"].each
          namespace: http://apiconnector.com
          source: 
        - - !ruby/object:SOAP::Mapping::Object

The above is a result from DotMailer's API, which I spent the last hour trying to figure out how to enumerate over the results. The above is the technique I used to figure out what the heck is going on. I think it beats using REXML etc this way, I could do something like this:

result['ListAddressBooksResult']['APIAddressBook'].each {|book| puts book["Name"]}

Well, I hope this helps anyone else who is looking.

/jason

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文