Adding soap element attributes

Hi,

I have a question that I hope will be simple for someone to answer.

I am using soap4r to write a simple library to consume web services from
an application. The application does not include a WSDL document, so I
have to write everything by hand.

The application requires attributes in certain elements of the soap
request, and I am having a little trouble figuring out how to do this.
So far, a portion of my test code looks like this:

driver = SOAP::RPC::Driver.new(endpoint, 'urn:namespace')
driver.add_method_as('get_account', 'GetAccountRequest', 'account')
get_account = driver.get_account('user@example.com')

which produces this:

<n2:GetAccountRequest xmlns:n2="urn:namespace"
       env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <account xsi:type="xsd:string">user@example.com</account>
</n2:GetAccountRequest>

but I need the soap request to look like this:

<n2:GetAccountRequest xmlns:n2="urn:namespace"
       env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <account by="name" xsi:type="xsd:string">user@example.com</account>
</n2:GetAccountRequest>

with the by="name" attribute in the account element.

I've been experimenting with SOAP::Mapping::Registry to achieve this,
but I am not sure how it would be done, or even if this is the correct
approach to take. If anyone can offer any assistance, it would be
appreciated.

Thanks,
Andrew

···

--
Posted via http://www.ruby-forum.com/.

Hi,

Andrew Tongen wrote:

I am using soap4r to write a simple library to consume web services from
an application. The application does not include a WSDL document, so I
have to write everything by hand.

Unlucky.

The application requires attributes in certain elements of the soap
request, and I am having a little trouble figuring out how to do this.
So far, a portion of my test code looks like this:

driver = SOAP::RPC::Driver.new(endpoint, 'urn:namespace')
driver.add_method_as('get_account', 'GetAccountRequest', 'account')
get_account = driver.get_account('user@example.com')

You need to set up a request object by yourself.

  ele = SOAP::SOAPString.new('user@example.com')
  ele.elename = XSD::QName.new(nil, 'account')
  ele.extraattr[XSD::QName.new(nil, 'by')] = 'name'
  driver.get_account(ele)

It must be a hard work when it comes to a complex request object. You
can write a WSDL from service definition first.

Regards,
// NaHi

Thanks Hiroshi, that got me started. Soap4r is great, I just wish this
app had a WSDL!

I may consider writing a WSDL for this application, but for now I only
need a subset of fucntionality. The request objects are all pretty
simple, but I am having trouble accessing data from the response
objects.

After calling:

get_account = driver.get_account('user@example.com')

The raw XML response for this command looks something like this:

<GetAccountResponse xmlns:ns0="urn:namespace">
  <account name="user@example.com"
id="770316d9-qwe4-38eu-s84h-2dfe3c6cc874">
    <a n="key1">value1</a>
    <a n="key2">value2</a>
    <a n="key3">value3</a>
    ...
  </account>
</GetAccountResponse>

I need to access the key/value pairs in the a attributes, but
get_account.account.a simply returns an array of [value1, value2,
value3, ...] and seems to ignore the attributes. Many response objects
for this app take this form, so it would be nice to be able to create a
hash, or ruby object dynamically based on the key/values.

Can I access the raw response XML somehow, or is there a better way to
do this?

The app I am using is Zimbra, in case anyone has any experience or
advice for use with Soap4r.

Thanks again,
Andrew

···

--
Posted via http://www.ruby-forum.com/.

Hi,

Andrew Tongen wrote:

I may consider writing a WSDL for this application, but for now I only
need a subset of fucntionality. The request objects are all pretty
simple, but I am having trouble accessing data from the response
objects.

After calling:

get_account = driver.get_account('user@example.com')

The raw XML response for this command looks something like this:

<GetAccountResponse xmlns:ns0="urn:namespace">
  <account name="user@example.com"
id="770316d9-qwe4-38eu-s84h-2dfe3c6cc874">
    <a n="key1">value1</a>
    <a n="key2">value2</a>
    <a n="key3">value3</a>
    ...
  </account>
</GetAccountResponse>

I need to access the key/value pairs in the a attributes, but
get_account.account.a simply returns an array of [value1, value2,
value3, ...] and seems to ignore the attributes. Many response objects
for this app take this form, so it would be nice to be able to create a
hash, or ruby object dynamically based on the key/values.

You need to define the service as a document service when you want to
handle XML attribute. Try the following.

  / / /

require 'soap/rpc/driver'

ns = 'urn:namespace'
soapaction = nil

driver = SOAP::RPC::Driver.new(nil, ns)
driver.add_document_method('get_account', soapaction,
  XSD::QName.new(ns, 'GetAccountRequest'),
  XSD::QName.new(ns, 'GetAccountResponse'))

driver.test_loopback_response << <<__XML__
<env:Envelope xmlns:env="Error;
  <env:Body>
    <GetAccountResponse xmlns:ns0="urn:namespace">
      <account name="user@example.com"
          id="770316d9-qwe4-38eu-s84h-2dfe3c6cc874">
        <a n="key1">value1</a>
        <a n="key2">value2</a>
        <a n="key3">value3</a>
      </account>
    </GetAccountResponse>
  </env:Body>
</env:Envelope>
__XML__
driver.wiredump_dev = STDOUT

ele = SOAP::SOAPString.new('user@example.com')
ele.elename = XSD::QName.new(nil, 'account')
ele.extraattr[XSD::QName.new(nil, 'by')] = 'name'
# !!! a wrapper element is needed for document service.
req = SOAP::SOAPElement.new(XSD::QName.new(ns, 'GetAccountRequest'))
req.add(ele)

get_account = driver.get_account(req)
map = {}
get_account.account.a.each do |value|
  map[value.xmlattr_n] = value
end
p map # => {"key1"=>"value1", "key2"=>"value2", "key3"=>"value3"}

# Now you want to write WSDL, don't you? :slight_smile:

The app I am using is Zimbra, in case anyone has any experience or
advice for use with Soap4r.

Please let me know if you succeeded to use it. Users must be interested
in it.

Regards,
// NaHi