EDevil has asked for the wisdom of the Perl Monks concerning the following question:

Hello all. I'm having a similar problem to this. Unfortunately, I couldn't figure out the solution from the thread. I'm calling a Web Service method which takes a sole ComplexType argument. The output I get is:
./complex.pl document/literal support is EXPERIMENTAL in SOAP::Lite at /usr/local/s +hare/perl/5.8.7/SOAP/Lite.pm line 2818. Type 'PublishRequest' can't be found in a schema class 'SOAP::Serializ +er'
I'm using SOAP::Data::ComplexType to build the argument.
Here is the WSDL:
<?xml version="1.0" encoding="UTF-8"?> <definitions name="SapoBroker" targetNamespace="http://services.mydomain.org/broker" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:typens="http://services.mydomain.org/broker" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"> <types> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespa +ce="http://services.mydomain.org/broker"> <complexType name="BrokerMessage"> <sequence> <element name="deliveryMode" type="int" /> <element name="priority" type="int" /> <element name="messageId" nillable="true" type="st +ring" /> <element name="correlationId" nillable="true" type +="string" /> <element name="timestamp" nillable="true" type="st +ring" /> <element name="expiration" nillable="true" type="s +tring" /> <element name="destinationName" nillable="true" ty +pe="string" /> <element name="textPayload" nillable="true" type=" +string" /> </sequence> </complexType> <complexType name="EnqueueRequest"> <sequence> <element name="brokerMessage" type="typens:BrokerM +essage" /> </sequence> </complexType> <complexType name="PublishRequest"> <sequence> <element name="brokerMessage" type="typens:BrokerM +essage" /> </sequence> </complexType> <element name="EnqueueRequestMessage" type="typens:Enqueue +Request" /> <element name="PublishRequestMessage" type="typens:Publish +Request" /> </schema> </types> <message name="enqueueMessageRequest"> <part element="typens:EnqueueRequestMessage" name="EnqueueRequ +estMessage" /> </message> <message name="publishMessageRequest"> <part element="typens:PublishRequestMessage" name="PublishRequ +estMessage" /> </message> <message name="BrokerOut" /> <portType name="BrokerApi"> <operation name="enqueue"> <input message="typens:enqueueMessageRequest" name="enqueu +eMessageRequest" /> <output message="typens:BrokerOut" name="enqueueOutput" /> </operation> <operation name="publish"> <input message="typens:publishMessageRequest" name="publis +hMessageRequest" /> <output message="typens:BrokerOut" name="publishOutput" /> </operation> </portType> <binding name="BrokerSoapBinding" type="typens:BrokerApi"> <soap:binding style="document" transport="http://schemas.xmlso +ap.org/soap/http" /> <operation name="enqueue"> <soap:operation soapAction="http://services.mydomain.org/b +roker/enqueue" /> <input name="enqueueMessageRequest"> <soap:body use="literal" /> </input> <output name="enqueueOutput"> <soap:body use="literal" /> </output> </operation> <operation name="publish"> <soap:operation soapAction="http://services.mydomain.org/b +roker/publish" /> <input name="publishMessageRequest"> <soap:body use="literal" /> </input> <output name="publishOutput"> <soap:body use="literal" /> </output> </operation> </binding> <service name="BrokerApiService"> <port binding="typens:BrokerSoapBinding" name="Broker"> <soap:address location="http://localhost:8000/broker/produ +cer" /> </port> </service> </definitions>
Here are the modules I created to represent a PublishRequest:
package PublishRequestType; use strict; use warnings; use SOAP::Data::ComplexType; use vars qw(@ISA); @ISA = qw(SOAP::Data::ComplexType); use constant OBJ_URI => 'http://services.mydomain.org/broker'; use constant OBJ_TYPE => 'ns1:PublishRequest'; use constant OBJ_FIELDS => { PublishRequest => [[ BrokerMessageType_inner::OBJ_TYPE, BrokerMess +ageType_inner::OBJ_FIELDS ], BrokerMessageType_inner::OBJ_URI, undef ] }; sub new { my $proto = shift; my $class = ref($proto) || $proto; my $data = shift; my $obj_fields = shift; $obj_fields = defined $obj_fields && ref($obj_fields) eq 'HASH' ? +{%{$obj_fields}, %{+OBJ_FIELDS}} : OBJ_FIELDS; my $self = $class->SUPER::new($data, $obj_fields); return bless($self, $class); } package BrokerMessageType_inner; use strict; use warnings; use SOAP::Data::ComplexType; use vars qw(@ISA); @ISA = qw(SOAP::Data::ComplexType); use constant OBJ_URI => 'http://services.mydomain.org/broker'; use constant OBJ_TYPE => 'ns1:PublishRequest'; use constant OBJ_FIELDS => { BrokerMessage => [[ BrokerMessageType::OBJ_TYPE, BrokerMessageType +::OBJ_FIELDS ], BrokerMessageType::OBJ_URI, undef ] }; sub new { my $proto = shift; my $class = ref($proto) || $proto; my $data = shift; my $obj_fields = shift; $obj_fields = defined $obj_fields && ref($obj_fields) eq 'HASH' ? +{%{$obj_fields}, %{+OBJ_FIELDS}} : OBJ_FIELDS; my $self = $class->SUPER::new($data, $obj_fields); return bless($self, $class); } package BrokerMessageType; use strict; use warnings; use SOAP::Data::ComplexType; use vars qw(@ISA); @ISA = qw(SOAP::Data::ComplexType); use constant OBJ_URI => 'http://services.mydomain.org/broker'; use constant OBJ_TYPE => 'ns1:BrokerMessage'; use constant OBJ_FIELDS => { deliveryMode => ['int', undef, undef], priority => ['int', undef, undef], messageId => ['string', undef, undef], correlationId => ['string', undef, undef], timestamp => ['string', undef, undef], expiration => ['string', undef, undef], destinationName => ['string', undef, undef], textPayload => ['string', undef, undef], }; sub new { my $proto = shift; my $class = ref($proto) || $proto; my $data = shift; my $obj_fields = shift; $obj_fields = defined $obj_fields && ref($obj_fields) eq 'HASH' ? +{%{$obj_fields}, %{+OBJ_FIELDS}} : OBJ_FIELDS; my $self = $class->SUPER::new($data, $obj_fields); return bless($self, $class); }
And here is the client code I use:
#!/usr/bin/perl -w package main; use strict; use Data::Dumper; use SOAP::Lite +trace => qw( debug ); use SOAP::Data::ComplexType; use BrokerMessageType; use BrokerMessageType_inner; use PublishRequestType; my $WSDL = 'file:///tmp/broker.wsdl'; my $soap = SOAP::Lite -> uri('http://services.mydomain.org/broker') -> service($WSDL); my $request_obj = PublishRequestType->new ({ PublishRequest => { BrokerMessage => { destinationName => 'blo +gs', textPayload => 'TES +T' }} }); $soap->publish($request_obj->as_soap_data);
By the way, $request_obj->as_xml_data prints this:
<?xml version="1.0" encoding="UTF-8"?> <SOAP:ENV xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <namesp1:PublishRequest xmlns:namesp1="http://services.mydomain.org/ +broker" xsi:type="ns1:PublishRequest"> <namesp2:BrokerMessage xsi:type="ns1:BrokerMessage" xmlns:namesp2= +"http://services.mydomain.org/broker"> <destinationName xsi:type="xsd:string">blogs</destinationName> <textPayload xsi:type="xsd:string">TEST</textPayload> </namesp2:BrokerMessage> </namesp1:PublishRequest> </SOAP:ENV>
SOAP::Lite::VERSION = 0.67
SOAP::Data::ComplexType::VERSION = 0.041

I'm sorry for the long post, but I wanted to give all the needed information. Thanks for the help.

Replies are listed 'Best First'.
Re: WebService client with SOAP::Lite and ComplexType
by shonorio (Hermit) on Jul 04, 2006 at 16:26 UTC
    Yes, information help-us a lot to understand what is wrong (if something are wrong), but you could use tag like readmore to don't take 'Seekers of Perl Wisdom' a large page.

    Solli Moreira Honorio
    Sao Paulo - Brazil
Re: WebService client with SOAP::Lite and ComplexType
by gellyfish (Monsignor) on Jul 05, 2006 at 10:28 UTC

    The WSDL would seem to indicate that you want to use PublishRequestMessage rather than PublishRequest and brokerMessage rather than BrokerMessage so you need to change your client to have:

    my $request_obj = PublishRequestType->new ({ PublishRequestMessage => { brokerMessage => { destinationName +=> 'blogs', textPayload => 'TES +T' }} });
    and also change the OBJ_FIELDS in PublishRequestType.pm and BrokerMessageType_inner.pm to reflect the change.

    /J\

      Thanks for the reply. I did exactly what you said but the problem remains. The request_obj->as_xml_data became:
      <?xml version="1.0" encoding="UTF-8"?> <SOAP:ENV xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <namesp1:PublishRequestMessage xmlns:namesp1="http://services.mydoma +in.org/broker" xsi:type="ns1:PublishRequestMessage"> <namesp2:brokerMessage xsi:type="ns1:brokerMessage" xmlns:namesp2= +"http://services.mydomain.org/broker"> <destinationName xsi:type="xsd:string">blogs</destinationName> <textPayload xsi:type="xsd:string">TEST</textPayload> </namesp2:brokerMessage> </namesp1:PublishRequestMessage> </SOAP:ENV>
      But running the client produces the same result:
      Type 'PublishRequest' can't be found in a schema class 'SOAP::Serializ +er'
      The <Body> tag is also missing... Any thoughts?

        Can you set use SOAP::Lite +trace => qw(debug); in the client and give us the entire output? The SOAP envelope I'm seeing here is different to what you have above and it's rather difficult not having the service you are using to test with.

        /J\

Re: WebService client with SOAP::Lite and ComplexType
by Anonymous Monk on Jul 04, 2006 at 23:25 UTC
    Perl is a great language, but avoid it when it comes to web service.

    Considered by Old_Gray_Bear: Useless Trollage; please delete
    Unconsidered by Arunbear: keep votes prevented reaping (Keep: 10, Edit: 0, Reap: 21)

      It would be more accurate to say:

      Perl is a great language, but avoid it when it comes to web service interaction in other languages.

      ie, it's fine to use SOAP::Lite -> SOAP::Lite, or even SOAP::Lite -> SOAP, but don't try mixing in gsoap, or any of the other SOAP toolkits w/out a whole bunch of headaches.

      The problem? It's not Perl -- it's almost all SOAP -- it's like the early days of CSS -- the specifications came out, lots of people wrote to how they understood the specifications, and lo and behold, everyone came up with different interpretations, thus their toolkits weren't compatable. When you start mixing in different encoding types, languages that don't support certain data types, or mixing loose and strict typed toolkits, you're going to have problems.

      Update: okay, before someone complains that the whole point of webservices is that it's intended to be language neutral, and so you're supposed to talk to other toolkits, yes, that's true. However, I've also run into other interaction problems in SOAP that didn't involve Perl, so it's not just a Perl thing -- it's bad implementations across the board. (I'm currently writing bad SOAP implementations in IDL, myself)

        It'd be even more accurate to say, soap is extremely compatable at a core level, but a few basic features are ambiguously implemented and some extensions are not cross-kit supported.

        I suggest using BP1 or WS1. http://xml.coverpages.org/ni2004-08-11-a.html

        Yes, it is not just a Perl thing, however Perl seems to be on the poor side among all the solutions. One of the major problem is that Perl SOAP is so out-of-dated, when other solutions are getting improved all the time.

        Interoperatability is an issue, but Perl seems to have much poorer interoperatability.

        Awhile back I heard some stupid comment saying that one should not complain about SOAP::Lite, because it is lite, and if one is a good programmer, why not just code from bottom up. That was one of the most stupid comment I have heard here. If everybody is going to code SOAP bottom up, then IT is not an industry.

        A good programmer is lazy, and with a good SOAP solution, you are even not aware of the existance of SOAP.