SOAP::Mapping::Object to string?

350 views
Skip to first unread message

Chris

unread,
Apr 10, 2006, 5:42:29 PM4/10/06
to soap4r
I have a SOAP client. It receives from the server an array of
SOAP::Mapping::Object objects. If I use "puts" on them, I can see 3 of
them:

#<SOAP::Mapping::Object:0x2ea9fe8>
#<SOAP::Mapping::Object:0x2e9b9c0>
#<SOAP::Mapping::Object:0x2e88b20>

I can subject these to "p" or "pp" and see what they are:

[#<SOAP::Mapping::Object:0x1719b58 {}MemberID=3 {}Name="foo3"
{}Address="bar3">,
#<SOAP::Mapping::Object:0x170f0ac {}MemberID=1 {}Name="foo1"
{}Address="bar1">,
#<SOAP::Mapping::Object:0x17059a4 {}MemberID=2 {}Name="foo2"
{}Address="bar2">]

But I can't seem to figure out how to use "to_s" on each element of the
array. Ultimately what I'd like to do is test that there are
particular values in particular array elements, and I need these
represented as strings to do that. I think.

-Chris

Emil Marceta

unread,
Apr 10, 2006, 10:24:38 PM4/10/06
to soa...@googlegroups.com

to_s is not generated in SOAP::Mapping::Object in a way you would like
to use it unfortunately. However to test the particular elements and their
properties just try accessing them, the accessor should have been generated.

for example, for a service that returns array (assumes 'test/unit' has
been required) :

svc.returnsArray().each { |elem| assert(elem.name == 'expectedname') }

emil

c3

unread,
Apr 13, 2006, 5:04:32 PM4/13/06
to soap4r
I seem to only get back SOAP::Mapping::Object objects from my wsdl4r
generated client (PayPal).

For earlier discussions is looked a though these responses were
supposed to get mapped back into the objects from the wsdl but then
there were some issues and then I'm not sure...

Been searching for 3 days now and all my hair is gone trying to get
even a simple connection working. Now that I'm connected and can send
requests I'm not sure what I'm supposed to do with the responses. Has
anyone found some documents on how to deal with the responses?

Thanks

Chris

unread,
Apr 13, 2006, 6:15:22 PM4/13/06
to soap4r
What do you need to do? I'm a tester, I'm subjecting the responses I
get from my app's SOAP server to various assert() methods to show that
it is behaving correctly.

I do find that my server is returning message objects in a very odd
form, so for now I'm doing my asserts against the returned object
subjected to #inspect, for example:

assert_match(/FooBar="foobar1"/,query1.inspect)

and that's good enough for me, for now.

The #inspect method is what "pp" uses when showing what's in the
object.

Hope that helps...
-Chris

Emil Marceta

unread,
Apr 13, 2006, 6:35:58 PM4/13/06
to soa...@googlegroups.com
On 4/13/06, Chris <christoph...@gmail.com> wrote:

> I do find that my server is returning message objects in a very odd
> form, so for now I'm doing my asserts against the returned object
> subjected to #inspect, for example:
>
> assert_match(/FooBar="foobar1"/,query1.inspect)
>
> and that's good enough for me, for now.

Whatever floats your boat. It was just a suggestion to use the interface
in the intended way.

SOAP::Mapping::Object is always returned on success calls, and it will
respond to the properties that are defined in the message.

cheers,
emil

Chris

unread,
Apr 13, 2006, 8:21:27 PM4/13/06
to soap4r
>Whatever floats your boat. It was just a suggestion to use the interface
>in the intended way.

:)

>SOAP::Mapping::Object is always returned on success calls, and it will
>respond to the properties that are defined in the message.

I don't think my message actually has real properties. I can't figure
out what those "{}"s are doing there. How would you address these?
For instance, assign "Name" to a variable "x"?

#<SOAP::Mapping::Object:0x2b0bfb8 {}MemberID=1 {}Name="foo1"
{}Address="bar1">

(and thanks again!)
-Chris

c3

unread,
Apr 13, 2006, 9:30:11 PM4/13/06
to soap4r
I need to iterate over the results but the best SOAP::Mapping:Object
offers is [] but what I really want to know is if this is expected
behavior. If it is I'll figure something out but if my install is
somehow broken I I've done something wrong I'd like to know that now
before I go and write something I'll have to throw away later.

Emil Marceta

unread,
Apr 14, 2006, 12:49:44 AM4/14/06
to soa...@googlegroups.com
On 4/13/06, Chris <christoph...@gmail.com> wrote:
>

The properties in the result represent the message elements and
are read only. The operation result is the structure (or array of structures)
and the structure correspond to the service message response defined
in wsdl.

Try something like this:

result = service.invoke(....) # I don't have your operation name handy.

Then try accessing: result.name or result.memberID or result.address
If it is the array then iterate, and access the properties on the array
element.

The '{}' is the namespace property of each element.

cheers,
emil

Chris

unread,
Apr 14, 2006, 11:35:26 AM4/14/06
to soap4r

Right, that's what I thought. What I'm getting back doesn't seem to be
an array, even though it looks like it should be:

####################
@result = @soap.selectStuff('Name=foo1')
@result.each do |result_obj|
puts result_obj.inspect
end

yields:

#<SOAP::Mapping::Object:0x2b02700 {}ID=5158 {}Name="foo1"
{}Address="16">
#<SOAP::Mapping::Object:0x2b01e84 {}ID=5160 {}Name="foo1"
{}Address="18">
#<SOAP::Mapping::Object:0x2b01608 {}ID=5161 {}Name="foo1"
{}lAddress="19">
#<SOAP::Mapping::Object:0x2b00d8c {}ID=5162 {}Name="foo1"
{}Address="20">
################
@result.each do |result_obj|
puts result_obj.Name
end

yields:
NoMethodError: undefined method `Name' for
#<SOAP::Mapping::Object:0x5618c18>
####################################
@result.each do |result_obj|
result_obj.each do |element|
puts element
end
end

yields:
NoMethodError: undefined method `each' for
#<SOAP::Mapping::Object:0x5618450>
##################################
You see the problem. Those objects returned don't seem to be arrays,
even though they do consist of 3 elements.

-Chris

Emil Marceta

unread,
Apr 14, 2006, 1:46:59 PM4/14/06
to soa...@googlegroups.com

Try modifying this

> @result.each do |result_obj|
> puts result_obj.Name
> end
>

to lowercase, such as this. This is

@result.each do |result_obj|
puts result_obj.name
end


The second snippet iteration iterates over array of arrays, and from
what we see so far it is an array of structures.


emil

Chris

unread,
Apr 14, 2006, 2:21:56 PM4/14/06
to soap4r
>to lowercase, such as this. This is
>
>@result.each do |result_obj|
> puts result_obj.name
>end

eh. same result:

NoMethodError: undefined method `name' for
#<SOAP::Mapping::Object:0x5618c00>

Emil Marceta

unread,
Apr 14, 2006, 3:12:38 PM4/14/06
to soa...@googlegroups.com
On 4/14/06, Chris <christoph...@gmail.com> wrote:
>

I see, you have some other problems then. The intended
way is be able to access the properties that represent the
message parts. Your wsdl probably shows what is the
problem. Could you post it?

emil

Chris

unread,
Apr 14, 2006, 3:46:59 PM4/14/06
to soap4r

It's that same giant wsdl as before. The actual values are "MemberID",
"ListName", and "EmailAddress".

Emil Marceta

unread,
Apr 14, 2006, 6:26:44 PM4/14/06
to soa...@googlegroups.com
On 4/14/06, Chris <christoph...@gmail.com> wrote:
>
>
> It's that same giant wsdl as before. The actual values are "MemberID",
> "ListName", and "EmailAddress".

This worked for me :
-----------------------------
....
svc = SOAP::WSDLDriverFactory.new(SERVICE_WSDL).create_rpc_driver
#svc.wiredump_dev = STDOUT

svc.selectSimpleMembers('domain=acme.org').each { |m|
p m.memberID, m.listName, m.emailAddress
}
----------------------------
The server returns sample array ArrayOfSimpleMemebersStruct.

emil

Chris

unread,
Apr 14, 2006, 6:48:56 PM4/14/06
to soap4r
oh, geez, I never capitalized it *that* way.
I'll look closely at the WSDL and figure out how to find this
information in the future.
Thanks yet again.
-Chris

c3

unread,
Apr 20, 2006, 2:17:26 AM4/20/06
to soap4r
One solution I have found to getting an using the elements values is to
use interpolation:

value = "#{response.element}"

It does the same thing as response.element.to_s but eval's the method
call rather than calling the class' to_s method. I'm using this in my
glue between the api client and the app to convert the values I want to
use from the response to something I can use as real values.

Another thing I learned that some might find useful is that when using
rails sessions you need to make sure you don't include ANY of the
wsdl2ruby generated driver stuff in your session:

class Foo
def initialize
@api = wsdl_driver.new
end
end
...

session[:bar] = Foo.new

is bad and nets you a couple of "singleton can't be dumped" errors at
best. You can't serialize any of the wsdl2ruby generated code. Think of
your driver as an IO object and you'll save hair.

Emil Marceta

unread,
Apr 20, 2006, 2:43:52 AM4/20/06
to soa...@googlegroups.com

Yep, this is a standard Ruby marshaling limitation. However there *is* a
way (although, may qualify as a grotesque hack) :)

In my RoR applications I use before / after filters to deserialise /
serialise the
session object to / from gzipped yaml format to overcome that problem. This
way I'm not required to create separate classes to deal with this issue.

The controller that needs to deal with non serializable objects extends
the below controller. That controllers offers methods for selecting which
session objects to apply the yaml / gzip. In the actual controller body
I simply mark those session objects to be treated that way :

gzip_session [:user, :cart]


class GzipSession < ActionController::Base
include ZlibMarshal

class << self
def session_objects
@session_objects ||= []
end

def gzip_session(sym)
a = sym.kind_of?(Array) ? sym : [sym]
a.each {|e| session_objects << e.to_sym }
logger.debug("Requested compress session objects: #{session_objects}")
end
end


def session_passivate
self.class.session_objects.each {|s|
if @session[s]
logger.debug("Gzip compress session: #{@session[s]}")
@session[s] = gz_dump(@session[s])
end
}
end

def session_activate
self.class.session_objects.each {|s|
if @session[s]
@session[s] = gz_load(@session[s])
logger.debug("Gzip decompressed session: #{@session[s]}")
end
}
end
end

# and here is the zlib / yaml module

module ZlibMarshal

def gz_dump(o)
zipper = Zlib::Deflate.new
zipped = zipper.deflate(YAML::dump(o), Zlib::FINISH)
zipper.close
zipped
end

def gz_load(o)
unzipper = Zlib::Inflate.new
unzipped = unzipper.inflate(o)
unzipper.close
YAML::load(unzipped)
end
end

Funny thay you mentioned that, we've been discussing this at the rails
wiki page recently:
http://wiki.rubyonrails.org/rails/pages/HowtoAvoidSessionRestoreError

cheers,
emil

Reply all
Reply to author
Forward
0 new messages