1

I am using SOAP::Lite to connect to an outside service. After much trial and error and communication with the other company, I have discovered the problem.

My code looks like this:

$soap = new SOAP::Lite
    ->service($wsdl_link)
    ->uri($url_link)
    ->proxy($proxy_link)
    ->on_action(sub { sprintf '"%s%s"', shift, shift });
my $resp = $soap->call('CreateAssignment',SOAP::Data->type('xml'=>$xml),
                                SOAP::Header->type('xml'=>$headXML));

This produces the following xml:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"   >
<soap:Header>
...
</soap:Header>
<soap:Body>
<CreateAssignment xmlns="url_link">
...
</CreateAssignment></soap:Body></soap:Envelope>

(where url_link is a valid url)

I need to define additional namespaces. I have done this by adding ->ns(namespace, prefix) to my code. However, this adds the additional namespaces to the "envelope" tag. I have been informed by the company that the namespaces need to be on the "CreateAssignment" tag. Indeed, when I make the appropriate change and run it using SOAP UI, it works beautifully.

I have tried adding the "CreateAssignment" tag to my xml and running the call() function without a method. SOAP::Lite wraps the xml in a generic tag.

I have read the SOAP::Lite documentation, I have asked search engines, I have asked colleagues and no one has an answer.

Is there a way to force SOAP::Lite to put the namespace declarations where I need them?

If not, what is a better module to use?

Emi R.
  • 11
  • 1
  • 4
  • Re "*I have been informed by the company that the namespaces need to be on the "CreateAssignment" tag.*", You are assigning namespaces to a prefix, right? (It wouldn't make sense any other way.) If so, the company is wrong. – ikegami Feb 03 '17 at 21:14

1 Answers1

0

I ended up sitting down with another coworker and reading the source code of SOAP::Lite - we discovered that the method tag was built in sub envelope. There is an if-statement whereby the module will use the entire object if instead of a string object a SOAP::Data object is passed in as the method:

elsif (UNIVERSAL::isa($method => 'SOAP::Data')) {
            $body = $method;
        }

I changed from this:

$soap = new SOAP::Lite
->service($wsdl_link)
->uri($url_link)
->proxy($proxy_link)
->on_action(sub { sprintf '"%s%s"', shift, shift });
my $resp = $soap->call('CreateAssignment',SOAP::Data->type('xml'=>$xml),
                                SOAP::Header->type('xml'=>$headXML));

To this:

$method = SOAP::Data->new(name=>'ns4:CreateAssignment');
$method->attr({'xmlns'=> $namespaceOne,
            'xmlns:ns2'=> $namespaceTwo,
            'xmlns:ns3'=> $namespaceThree,
            'xmlns:ns4'=> $namespaceFour,
            'xmlns:ns5'=> $namespaceFive});

$soap = new SOAP::Lite
        ->service($wsdl_link)
        ->uri($url_link)
        ->proxy($proxy_link)
        ->on_action(sub { sprintf '"%s%s"', shift, shift });

my $resp = $soap->call($method,SOAP::Data->type('xml'=>$xml),
                                SOAP::Header->type('xml'=>$headXML));

This created my method tag exactly as the company required:

<ns4:CreateAssignment xmlns="namespaceOne" xmlns:ns2="namespaceTwo" xmlns:ns3="namespaceThree" xmlns:ns4="namespaceFour" xmlns:ns5="namespaceFive">
...
</ns4:CreateAssignment>
Emi R.
  • 11
  • 1
  • 4