phpzend-frameworksoapwsdlzend-soap

How to add the namespace to all elements that get returned WSDL / SOAP


I'm fairly new to the SOAP and WSDL world. What do I have to do, to make sure that the namespace will always be in the return-element?

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://someurl.com">
    <SOAP-ENV:Body>
        <ns1:sayHelloResponse>
            <return>Say Hello Kelvin</return>
        </ns1:sayHelloResponse>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

What I want is:

<ns1:sayHelloResponse>
    <ns1:return>Say Hello Kelvin</ns1:return>
</ns1:sayHelloResponse>

I'm using PHP and the Zend Framework. The WSDL gets generated by Zend_Soap_AutoDiscovery. This shouldn't be a barrier though, because I will modify the output of it anyways.

Thanks for your help.


Solution

  • After taking a break for a while, I approached the problem once again. This time though, I stumbled upon this nice article (credits to my former co-worker Mike). If the attribute elementFormDefault isn't declared in the schema tag, unqualified is assumed as its value. By giving it the value "qualified" the following will happen:

    But if you add elementFormDefault="qualified" to all of the schemas in the document/literal wrapped WSDL, then all elements in the messages would be qualified with their parent's namespace.

    In general, you do not want to use elementFormDefault="qualified" because it bloats the messages, but a year or more ago there were interoperability issues between various vendors, and setting this attribute sometimes fixed the problems.

    Even though I wasn't using document/literal, I wanted to try it out. I added the attribute to my schema tag and made a request to a different call. Here's the response I got:

      <ns1:getUserResponse>
         <return>
            <ns1:firstname>First</ns1:firstname>
            <ns1:lastname>Last</ns1:lastname>
         </return>
      </ns1:getUserResponse>
    

    As you can see, the child elements of the "return"-element got the namespace prefixed. At this point I got really excited, because I finally got closer to where I wanted to be. Unfortunately, the return element didn't have the namespace prefixed. I tried the earlier call (see question post) again, but the response was the same as before.

    I couldn't spend more time on this issue. It was just a prototype after all. That's why I decided to hook into Zend_Soap_Server's handle function, to modify the response before outputting it.

    class Custom_Soap_Server extends Zend_Soap_Server 
    {
        public function __construct($wsdl = null, array $options = null)
        {
            parent::__construct($wsdl, $options);
    
            // Response of handle will always be returned
            $this->setReturnResponse(true); 
        }
    
        public function handle($request = null)
        {
            $response = parent::handle($request);
            echo str_replace(array('<return>', '</return>'), array('<ns1:return>', '</ns1:return>'), $response);
            return;
        }
    }
    

    To be honest, it's a nasty hack. I'm always assuming that there's just one namespace. The replace function could be written much better. But it was for a prototype after all and this was my first thought to make it work.

    After using the new custom class instead of Zend_Soap_Server, all of the return elements had ns1 prefixed to them.