如何从ruby客户端解析SOAP响应?

我正在学习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=[#, #, #, #, #, #] >>>>>>> {urn:schemas-microsoft-com:xml-diffgram-v1}diffgram=#<SOAP::Mapping::Object:0x80abe6c4 {}NewDataSet=#<SOAP::Mapping::Object:0x80ac1220 {}Table=[#, #<SOAP::Mapping::Object:0x80b778f4 {}FullName="Feiffer, Jules" {}BirthDate="01/26/1929" {}DeathDate=# {}Age="81" {}KnownFor="Cartoonists" {}DeadOrAlive="Alive">]>>>> 

我很难找出如何解析并在一个漂亮的表中显示返回的信息,甚至只是如何遍历记录并访问每个元素(即FullName,Age等)。 我经历了整个“getTodaysBirthdaysResult.methods – Object.new.methods”并继续努力尝试找出如何访问元素,但后来我进入arrays,我迷路了。

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

如果你打算解析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 

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

嗯,这是我的建议。

问题是,你必须抓住结果的正确部分,这是你可以实际迭代的东西。 不幸的是,世界上所有的检查都无济于事,因为它是一大堆难以理解的文本。

我这样做是:

 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"]} 

好吧,我希望这可以帮助任何正在寻找的人。

/杰森