This post is to document my particular workaround to this interoperability issue. To sum up the problem: PHP follows the SOAP 1.1 guidelines in defining array types when it defines them as being a type derived from "SOAP-ENC:Array". However, servers written in other languages (Java on Oracle in my case) have problems interpreting the PHP-generated arrays because they have no knowledge of the derived types, since those types are defined in the WSDL, not in the server code. This problem affects arrays in general, not just arrays of complex types. It is my oh-so-humble (and rather naive too, I'm sure) opinion that PHP should NOT use derived types, but there are probably edge cases where that is necessary, and that's the reason PHP does it that way. Makes it rather difficult when no other SOAP server implementation handles derived types. OK, OK, so I don't know for sure that NO other implementation handles derived types, I just mean that Java, .NET, and C++ implementations don't. Keep the flames low.... :-) Because I am also writing my own server, my workaround was to implement a pre-filter that looks for instances of derived array types and replaces them with "SOAP-ENC:Array". This actually works rather well, although it's not a "real" solution. For those who do not have access to the server, the most prevalent workaround I've seen is to hand-build the request and send it using SoapClient->__doRequest(). The problem with that approach is that it's tedious and fragile: if the specs change, you need to change your code. As an alternative, perhaps the following will work: - Construct the request normally. - Send the request, trapping for errors. - If you get an error indicating that the server did not recognize the array type (in my case, it's a deserialization error), do the following: - Extract the request into a variable using Soapclient->__getLastRequest(). - Replace every instance of xsi:type="<your namespace>:ArrayOf<array contents>" with xsi:type="<SOAP-ENC namespace>:Array" (you'll probably have to find and use the local name of the SOAP-ENC namespace, rather than assuming it's going to be "SOAP-ENC"). - Send another request using SoapClient->__doRequest(), passing it the now-massaged previous request. This requires you to know the endpoint url and SOAP action, information you can get from the WSDL. Or perhaps SoapClient->__getLastRequestHeaders() can help here... The really strong point of this approach is that it enables you to ignore the rest of the underlying SOAP structure, allowing your code to more easily handle changing specifications. The obvious problem with this approach is the lag time introduced by the initial unsuccessful request. If a significant number of your requests involve arrays, perhaps you can instantiate your SoapClient object with localhost (or some other bogus hostname) for the location, allow it to make the initial request, which should be very fast now, since it will simply return host not found, or a similar error, then do the massaging and re-sending. I don't know of any way to get the request content before sending. Well, that's where I am at this point. I'd appreciate any other suggestions/insight/corrections. Thanks, -Peter ""Peter Guy"" <pguy@vrcis.com> wrote in message 31.A0.13436.07F3DC34@pb1.pair.com">news:31.A0.13436.07F3DC34@pb1.pair.com... > I posted this last night, but it hasn't shown up, so I'm posting it again... > My apologies if this ends up being a double post. > > This seems to be a recurring problem, but I have yet to find an answer. > > I have implemented a web service written in Java, hosted on an Oracle > Application Server (version 9.0.4). > The web service makes heavy use of custom objects, written as Java Beans on > the server-side, and implemented as complex types in the WSDL. > > Using PHP 5.1.2 with its built-in SOAP implementation, I am able to consume > the WSDL w/out errors and make most calls using PHP classes to emulate the > WSDL's complex types. The problem comes in when a transaction requires an > array of one of the complex types. > Java-based clients have no problems; neither do .NET-based ones. > > I built a simple example that illustrates the problem; let's get right into > it. This is a live example, so you can do some testing on your own if you'd > like. > > The service is here: > http://vrcweb1.vrcis.com/custserv/CustomerService > The WSDL can be found here: > http://vrcweb1.vrcis.com/custserv/CustomerService?WSDL > > There is one operation: EchoBars. It accepts an array of Bar objects, then > returns that array. > The Bar object has one field: NAME, of type string. > > This is the PHP code I use to invoke EchoBars: > > $WSDL = "http://vrcweb1.vrcis.com/custserv/CustomerService?WSDL"; > $client = new SoapClient($WSDL); > $b1 = new Bar(); > $b1->NAME = "bar none"; > try{$client->EchoBars(array(1=>$b1));}catch(Exception $Ex){echo $Ex;} > > This is the request it generates: > > <?xml version="1.0" encoding="UTF-8"?> > <SOAP-ENV:Envelope > xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" > xmlns:ns1="CustomerService" > xmlns:ns2="http://www.vrcis.com/CustomerServiceAPIV1" > xmlns:xsd="http://www.w3.org/2001/XMLSchema" > xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" > xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" > SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> > <SOAP-ENV:Body> > <ns1:EchoBars> > <BARS > SOAP-ENC:arrayType="ns2:Bar[1]" > xsi:type="ns2:ArrayOfBar"> > <item xsi:type="ns2:Bar"> > <NAME xsi:type="xsd:string">bar none</NAME> > </item> > </BARS> > </ns1:EchoBars> > </SOAP-ENV:Body> > </SOAP-ENV:Envelope> > > Which request returns this error message: > > No Deserializer found to deserialize a > http://www.vrcis.com/CustomerServiceAPIV1:ArrayOfBar using encoding style > http://schemas.xmlsoap.org/soap/encoding/. > > > Here is a request that works: > > <?xml version='1.0' encoding='UTF-8'?> > <SOAP-ENV:Envelope > xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" > xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" > xmlns:xsd="http://www.w3.org/2001/XMLSchema"> > <SOAP-ENV:Body> > <ns1:EchoBars > xmlns:ns1="CustomerService" > SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> > <BARS > xmlns:ns2="http://schemas.xmlsoap.org/soap/encoding/" > xsi:type="ns2:Array" > xmlns:ns3="http://www.vrcis.com/CustomerServiceAPIV1" > ns2:arrayType="ns3:Bar[1]"> > <item xsi:type="ns3:Bar"> > <NAME xsi:type="xsd:string">bar none</NAME> > </item> > </BARS> > </ns1:EchoBars> > </SOAP-ENV:Body> > </SOAP-ENV:Envelope> > > Notice that the only real difference between the two requests is the "type" > of the BARS element. In the PHP-generated one it is "<my > namespace>:ArrayOfBar", while it is "<SOAP-ENC namespace>:Array" in the > other one. > There are other differences, but they are all naming conventions and don't > apply. > > To generate another request that works, goto > http://www.soapclient.com/soaptest.html. It'll generate a request that is > substantively the same as the one above. > > I think I know what's happening, I just don't know why, or if there's a way > to make it "happen" correctly. Or some way to reformat my WSDL so that PHP > interprets it correctly. > > The way I understand it, in the WSDL, arrays of complex types are defined > with a level of indirection: > > <complexType name="Bar"> > </complexType> > <complexType name="ArrayOfBar"> > <attribute arrayType="Bar[]"/> > </complexType> > > It seems to work kinda like pointers in C: ArrayOfBar is a reference to an > array of Bar objects. > > What appears to be happening is that PHP is not following that reference, > but is instead grabbing the value of the variable rather than dereferencing > it and using _that_ value (to use pointer lingo). > > > Naturally, the server replies (to the PHP-generated request), "I have no > idea what an 'ArrayOfBar'-type object is". > > So, my questions: > > 1. Is the WSDL formatted the right way for PHP? Could it be formatted > differently, so as to coerce PHP into supplying the correct "type" for the > BARS element? > 2. Is there any option or flag in PHP's SOAP implementation that will set up > PHP to read the WSDL differently? > 3. Is there a better way (other than an array) to implement a parameter that > is a collection of complexTypes? > 3. Does anyone know what the heck I'm talking about? ;-) > > Thanks, > > -Peter -- PHP Soap Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php