Re: Re: Java/Oracle server, PHP 5.1.2 client, array ofcomplexTypes, Deserializer error

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Nice Katy!

Overloading the SoapClient object is a very elegant workaround.

I'm assuming that every call to SoapClient->[specific web method] eventually
goes through __doRequest()?

For example, the invocation:
$client = new DotNetSoapClient($wsdl);
$client->MyMethod($param1, $param2);
will eventually trigger the overloaded __doRequest() method?

Neat, you can manipulate the request any way you want.

I don't think I'd recommend removing the xsi:type attributes, as they may be
needed by the server, but you certainly could replace them with the
"correct" type definition ("SOAP-ENC:Array").  The implementation would be a
bit fragile, as it would rely in PHP always using the string "SOAP-ENC" as
the local name for the soap encoding namespace, but that's probably
something upon which we can rely.

-Peter

"Katy Coe" <info@intelligentstreaming.com> wrote in message
5.2.1.1.2.20060121010629.00bc5d48@mail.intelligentstreaming.com">news:5.2.1.1.2.20060121010629.00bc5d48@mail.intelligentstreaming.com...
> Hi everyone,
>
> I'm using PHP 5.1.x as a client and .NET 1.1 as a server; I also am
writing
> both the client and server end of my application. While running basic
tests
> I noticed this problem too, just with arrays of simple types like int and
> string, .NET's deserialiser will complain "No type associated with Xml key
> <yournamespace> ArrayOfString" or some such.
>
> As has already been discussed in the thread, I traced the problem to the
> xsi:type attribute generated by PHP on the element in the SOAP request
that
> wraps all the array items. I don't know if this is a PHP bug or a
.NET/Java
> bug as I'm not a SOAP guru, but the very simple workaround I made goes as
> follows:
>
> class DotNetSoapClient extends SoapClient
> {
>      public function __construct($wsdl, $options = array()) {
>          parent::__construct($wsdl, $options);
>      }
>
>      public function __doRequest($request, $location, $action, $version)
>      {
>          $dom = DOMDocument::loadXML($request);
>          $xpath = new DOMXPath($dom);
>
>          // Array serialisation: remove the xsi:type attribute from all
> arrays encoded using SOAP-ENC:arrayType
>          // as this causes an "no type associated with Xml key"-type SOAP
> server error in .NET
>          $nodes =
> $xpath->query('/SOAP-ENV:Envelope/SOAP-ENV:Body/*//*[@SOAP-ENC:arrayType
> and @xsi:type]');
>
>          foreach ($nodes as $node)
>              $node->removeAttribute('type');
>
>          $request = $dom->saveXML();
>          return parent::__doRequest($request, $location, $action,
> $version);
>      }
> }
>
> This workaround:
>
> 1. Requires no underlying knowledge of SOAP protocol to use (does not
> require you to form your own SOAP request)
> 2. Works with .NET and I assume works or is easily adapted for Java
> 3. Only generates one request/response roundtrip over the network
> 4. Can be used if you don't have access to the server
>
> Since most web services in the real world use Java or .NET, I think that -
> even if this is a bug in their implementations and not PHP's - that it
> might be wise to at least include a flag in future versions of ext/soap
> that would allow the client developer to control how the request is
> serialised ("interop mode" or some such). From my naive perspective, that
> would seem to be a good compromise.
>
> Hope the workaround helps someone anyway :-)
>
> Katy.
>
> At 08:18 PM 01/20/2006, Peter Guy wrote:
> >Dmitry,
> >
> >Thank you for your attention to this thread.
> >
> >I have indeed applied a workaround to the server: added a pre-filter to
the
> >servlet that finds and changes PHP's array typing to something the server
> >understands.  Check out message 2083 (http://news.php.net/php.soap/2083)
for
> >more details.
> >
> >Thank you for considering a change in this area of PHP's SOAP
> >implementation.  Overall, I am impressed with PHP's SOAP implementation.
> > From the PHP developer's point of view, it's simple, elegant, and easy
to
> >use.  Just feed it a WSDL and you're off and running.  This array type
> >definition issue has been the only implementation problem with which I've
> >had to deal.
> >
> >-Peter
> >
> >""Dmitry Stogov"" <dmitry@zend.com> wrote in message
> >000101c61d99$b5686f80$6e02a8c0@thinkpad">news:000101c61d99$b5686f80$6e02a8c0@thinkpad...
> >Hi Peter,
> >
> >Right now ext/soap hasn't workaround for this problem.
> >I'll look and may be will create it later.
> >
> >Note that some other SOAP implementations have the same interopability
> >issue.
> >Look into google.
> >
>
>http://www.google.com/search?hl=en&rls=GGLD%2CGGLD%3A2005-13%2CGGLD%3Aen&q=
%
> >2B%22No+Deserializer+found+to+deserialize+a%22+%2Barray&lr=
> >
> >May be you will find a way to fix the server itself.
> >
> >Thanks. Dmitry.
> >
> > > -----Original Message-----
> > > From: Peter Guy [mailto:pguy@vrcis.com]
> > > Sent: Wednesday, January 18, 2006 10:45 PM
> > > To: soap@lists.php.net
> > > Subject: Re:  Re: Java/Oracle server, PHP 5.1.2 client,
> > > array of complexTypes, Deserializer error
> > >
> > >
> > > Thanks for the clarification, Dmitry.
> > >
> > > I see that it is legal to type a SOAP array the way that PHP
> > > does it, but I don't think it's the right way to do it. :-)
> > >
> > > The problem is, how will the SOAP server with which I'm
> > > dealing have any knowledge of the "type derived there from"?
> > > Unless it's written in PHP, it doesn't necessarily parse
> > > requests against the schema in the WSDL, so it likely won't
> > > have any knowledge of that derived type.
> > >
> > > So, is there any way to cajole PHP into defining arrays with
> > > a "SOAP-ENC:Array" type rather than the "type derived there
> > > from"?  Perhaps formatting the WSDL differently, like using
> > > elements rather than complex types?
> > >
> > > Any suggestions?
> > >
> > > -Peter
> > >
> > > ""Dmitry Stogov"" <dmitry@zend.com> wrote in message
> > > 000001c61c06$4bfd97d0$6e02a8c0@thinkpad">news:000001c61c06$4bfd97d0$6e02a8c0@thinkpad...
> > > > H Peter,
> > > >
> > > > This is well known issue, but not a php/soap bug.
> > > > The problem that some SOAP implementations don't confirm to SOAP
> > > > specification and don't accept types derived from array.
> > > >
> > > > See: http://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383522
> > > >
> > > > "SOAP arrays are defined as having a type of "SOAP-ENC:Array" or A
> > > > TYPE DERIVED THERE FROM."
> > > >
> > > > Thanks. Dmitry.
> > > >
> > > > > -----Original Message-----
> > > > > From: Peter Guy [mailto:pguy@vrcis.com]
> > > > > Sent: Wednesday, January 18, 2006 3:52 AM
> > > > > To: soap@lists.php.net
> > > > > Subject:  Re: Java/Oracle server, PHP 5.1.2 client,
> > > array of
> > > > > complexTypes, Deserializer error
> > > > >
> > > > >
> > > > > Since this is such a long post, I'll put all of my
> > > comments up here,
> > > > > rather than throughout the post or at the bottom.
> > > > >
> > > > > Thanks for taking the time to generate more stubs, and
> > > confirming my
> > > > > suspicions that this is a PHP bug, Michael.
> > > > >
> > > > > However, you state that, "The error is that php names the
> > > individual
> > > > > structs/complex types item...", but I'm pretty sure the
> > > error is in
> > > > > the xsi:type attribute of the BARS element.  PHP fills
> > > the xsi:type
> > > > > attribute with "<my
> > > > > namespace>:ArrayOfBar", when it should be "<SOAP-ENC :Array".
> > > > > Every other client I've seen specifies the type of an
> > > array element
> > > > > as "<SOAP-ENC namespace>:Array", so I'm almost sure that
> > > this is a
> > > > > PHP bug.
> > > > >
> > > > > Where do I go from here?  Shall I submit a PHP bug report?
> > > > >
> > > > > -Peter
> > > > >
> > > > > "Michael Rasmussen" <mir@miras.org> wrote in message
> > > > > pan.2006.01.18.00.19.56.504455@miras.org">news:pan.2006.01.18.00.19.56.504455@miras.org...
> > > > > > On Tue, 17 Jan 2006 11:04:21 -0800, Peter Guy wrote:
> > > > > >
> > > > > > > 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?
> > > > > > Well, it seems to be correct wsdl. mono(C#) and
> > > > > gsoap(c/c++) has now
> > > > > > problems in creating a correct proxy: The mono proxy:
> > > > > >
> > > > > //
> > > > > --------------------------------------------------------------
> > > > > -----------
> > > > > -----
> > > > > > //  <autogenerated>
> > > > > > //      This code was generated by a tool.
> > > > > > //      Mono Runtime Version: 1.1.4322.2032
> > > > > > //
> > > > > > //      Changes to this file may cause incorrect behavior
> > > > > and will be lost
> > > > > if
> > > > > > //      the code is regenerated.
> > > > > > //  </autogenerated>
> > > > > >
> > > > > //
> > > > > --------------------------------------------------------------
> > > > > -----------
> > > > > -----
> > > > > >
> > > > > > //
> > > > > > // This source code was auto-generated by Mono Web Services
> > > > > > Description
> > > > > Language Utility
> > > > > > //
> > > > > >
> > > > > > /// <remarks/>
> > > > > >
> > > [System.Web.Services.WebServiceBinding(Name="CustomerServicePort",
> > > > > Namespace="http://CustomerService.wsdl";)]
> > > > > > [System.Diagnostics.DebuggerStepThroughAttribute()]
> > > > > > [System.ComponentModel.DesignerCategoryAttribute("code")]
> > > > > > [System.Xml.Serialization.SoapInclude(typeof(Bar))]
> > > > > > public class CustomerService :
> > > > > System.Web.Services.Protocols.SoapHttpClientProtocol {
> > > > > >
> > > > > >     public CustomerService() {
> > > > > >         this.Url =
> > > > > "http://vrcweb1.vrcis.com/custserv/CustomerService";;
> > > > > >     }
> > > > > >
> > > > > >     [System.Web.Services.Protocols.SoapRpcMethodAttribute("",
> > > > > RequestNamespace="CustomerService",
> > > > > ResponseNamespace="CustomerService")]
> > > > > >     [return: System.Xml.Serialization.SoapElement("return")]
> > > > > >     public Bar[] EchoBars(Bar[] BARS) {
> > > > > >         object[] results = this.Invoke("EchoBars", new
> > > object[] {
> > > > > >             BARS});
> > > > > >         return ((Bar[])(results[0]));
> > > > > >     }
> > > > > >
> > > > > >     public System.IAsyncResult BeginEchoBars(Bar[] BARS,
> > > > > System.AsyncCallback callback, object asyncState) {
> > > > > >         return this.BeginInvoke("EchoBars", new object[] {
> > > > > >             BARS}, callback, asyncState);
> > > > > >     }
> > > > > >
> > > > > >     public Bar[] EndEchoBars(System.IAsyncResult asyncResult) {
> > > > > >         object[] results = this.EndInvoke(asyncResult);
> > > > > >         return ((Bar[])(results[0]));
> > > > > >     }
> > > > > > }
> > > > > >
> > > > > > /// <remarks/>
> > > > > >
> > > > > [System.Xml.Serialization.SoapType(Namespace="http://www.vrcis
> > > > > .com/CustomerS
> > > > > erviceAPIV1")]
> > > > > > public class Bar {
> > > > > >
> > > > > >     /// <remarks/>
> > > > > >     public string NAME;
> > > > > > }
> > > > > >
> > > > > > The gsoap proxy:
> > > > > > /** @mainpage CustomerService Definitions
> > > > > >
> > > > > > @section CustomerServiceBinding Service Binding
> > > > > > "CustomerServiceBinding"
> > > > > >
> > > > > > @subsection CustomerServiceBinding_operations Operations
> > > > > >
> > > > > >   - @ref ns1__EchoBars
> > > > > >
> > > > > > @subsection CustomerServiceBinding_ports Endpoint Ports
> > > > > >
> > > > > >   - http://vrcweb1.vrcis.com/custserv/CustomerService
> > > > > >
> > > > > > */
> > > > > >
> > > > > > //  Note: modify this file to customize the generated data type
> > > > > declarations
> > > > > >
> > > > > > //gsoapopt w
> > > > > > #import "stl.h"
> > > > > > /// Built-in attribute "SOAP-ENC:arrayType"
> > > > > > typedef char *SOAP_ENC__arrayType;
> > > > > >
> > > > > > /*
> > > > > > To customize the names of the namespace prefixes generated
> > > > > by wsdl2h,
> > > > > modify
> > > > > > the prefix names below and add the modified lines to
> > > typemap.dat
> > > > > > to run
> > > > > wsdl2h:
> > > > > >
> > > > > > ns2 = http://www.vrcis.com/CustomerServiceAPIV1
> > > > > > */
> > > > > >
> > > > > > //gsoap ns2   schema namespace:
> > > > > http://www.vrcis.com/CustomerServiceAPIV1
> > > > > > //gsoap ns2   schema form: unqualified
> > > > > >
> > > > > > // Forward declarations
> > > > > > class ArrayOfBar;
> > > > > > class ns2__Bar;
> > > > > >
> > > > > > // End of forward declarations
> > > > > >
> > > > > >
> > > > > > /// Schema http://www.vrcis.com/CustomerServiceAPIV1
> > > > > complexType "Bar"
> > > > > >
> > > > > > class ns2__Bar
> > > > > > { public:
> > > > > > /// Element NAME of type xs:string
> > > > > >     std::string                          NAME
> > > > >            ;
> > > > > ///< Required element
> > > > > > /// A handle to the soap struct context that manages this
> > > > > class instance
> > > > > >     struct soap                         *soap
> > > > >            ;
> > > > > > };
> > > > > >
> > > > > > /// Schema http://www.vrcis.com/CustomerServiceAPIV1 complexType
> > > > > "ArrayOfBar"
> > > > > >
> > > > > > /// SOAP encoded array of
> > > > > > "http://www.vrcis.com/CustomerServiceAPIV1":Bar
> > > > > > class ArrayOfBar
> > > > > > { public:
> > > > > > /// Pointer to an array of ns2__Bar*
> > > > > >     ns2__Bar*                           *__ptr
> > > > >            ;
> > > > > > /// Size of the dynamic array
> > > > > >     int                                  __size
> > > > >            ;
> > > > > > /// A handle to the soap struct context that manages this
> > > > > class instance
> > > > > >     struct soap                         *soap
> > > > >            ;
> > > > > > };
> > > > > >
> > > > > > //gsoap ns1  service name: CustomerServiceBinding
> > > > > > //gsoap ns1  service type: CustomerServicePortType //gsoap ns1
> > > > > > service port:
> > > > > http://vrcweb1.vrcis.com/custserv/CustomerService
> > > > > > //gsoap ns1  service namespace: CustomerService
> > > > > >
> > > > > > /// Operation response struct "ns1__EchoBarsResponse"
> > > of service
> > > > > > binding
> > > > > "CustomerServiceBinding" operation "ns1__EchoBars"
> > > > > > struct ns1__EchoBarsResponse
> > > > > > {
> > > > > >     ArrayOfBar*                         return_;
> > > > > > };
> > > > > >
> > > > > > /// Operation "ns1__EchoBars" of service binding
> > > > > > "CustomerServiceBinding"
> > > > > >
> > > > > > /**
> > > > > >
> > > > > > Operation details:
> > > > > >
> > > > > >   - SOAP RPC
> > > > > encodingStyle="http://schemas.xmlsoap.org/soap/encoding/";
> > > > > >
> > > > > > C stub function (defined in soapClient.c[pp]):
> > > > > > @code
> > > > > >   int soap_call_ns1__EchoBars(struct soap *soap,
> > > > > >     NULL, // char *endpoint = NULL selects default endpoint for
> > > > > > this
> > > > > operation
> > > > > >     NULL, // char *action = NULL selects default action for
> > > > > this operation
> > > > > >     ArrayOfBar*                         BARS,
> > > > > >     struct ns1__EchoBarsResponse&
> > > > > >   );
> > > > > > @endcode
> > > > > >
> > > > > > C++ proxy class (defined in soapCustomerServiceBindingProxy.h):
> > > > > >   class CustomerServiceBinding;
> > > > > >
> > > > > > */
> > > > > >
> > > > > > //gsoap ns1  service method-style: EchoBars rpc
> > > > > > //gsoap ns1  service method-encoding: EchoBars
> > > > > http://schemas.xmlsoap.org/soap/encoding/
> > > > > > //gsoap ns1  service method-action: EchoBars ""
> > > > > > int ns1__EchoBars(
> > > > > >     ArrayOfBar*                         BARS,
> > > > > >     struct ns1__EchoBarsResponse& );
> > > > > >
> > > > > > /*  End of CustomerService Definitions */
> > > > > >
> > > > > > Parsing output from php:
> > > > > > Supported functions:
> > > > > > ArrayOfBar EchoBars(ArrayOfBar $BARS)
> > > > > > Supported types:
> > > > > > Bar ArrayOfBar[]
> > > > > > struct Bar {
> > > > > >  string NAME;
> > > > > > }
> > > > > > Produced with this code:
> > > > > >     $client = new SoapClient(
> > > > > >     'http://vrcweb1.vrcis.com/custserv/CustomerService?WSDL',
> > > > > >     $options
> > > > > >     );
> > > > > >     if ($functions = $client->__getFunctions())
> > > > > >     {
> > > > > >     echo "Supported functions:\n";
> > > > > >     foreach ($functions as $function)
> > > > > >     echo $function, "\n";
> > > > > >     }
> > > > > >     if ($types = $client->__getTypes())
> > > > > >     {
> > > > > >     echo "Supported types:\n";
> > > > > >     foreach ($types as $type)
> > > > > >     echo $type, "\n";
> > > > > >     }
> > > > > >
> > > > > > The reason that it is not working in php is a bug in the proxy
> > > > > > that php is creating!
> > > > > >
> > > > > > The request sent:
> > > > > > <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>
> > > > > >
> > > > > > This is how it should be - which your http-client
> > > > > demonstrates: <BARS
> > > > > > SOAP-ENC:arrayType="ns1:Bar[1]" xsi:type="SOAP-ENC:Array">
> > > > > >   <Bar xsi:type="ns1:Bar">
> > > > > >     <NAME xsi:type="xsd:string">String Value</NAME>
> > > > > >   </Bar>
> > > > > > </BARS>
> > > > > >
> > > > > > The error is that php names the individual structs/complex
> > > > > types item
> > > > > > but they must be named Bar. The error is therefore on the
> > > > > client side
> > > > > > (php) which does not send a correct formated request. I am
> > > > > possitively
> > > > > > convinced that receiving will work as can be seen under
> > > supported
> > > > > > types above. You could try sending a raw xml request to your
> > > > > > server but let php handle the response to have this observation
> > > > > > confirmed.
> > > > > >
> > > > > > --
> > > > > > Hilsen/Regards
> > > > > > Michael Rasmussen
> > > > > >
> > > > >
> > > http://keyserver.veridis.com:11371/pks/lookup?op=get&search=0xE3E809
> > > > > 17

-- 
PHP Soap Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php


[Index of Archives]     [PHP Home]     [PHP Users]     [Kernel Newbies]     [PHP Database]     [Yosemite]

  Powered by Linux