Hi,

I would like to ask some comments on the following issue. Thanks in advance for your help.
It is about to consume a web service on PHP5 with SOAP extension (No Nusoap). The example is to parse a last name to web service and get all the contacts that has the same last name, then display the result on the page. Each set of result should have ID, last name, and first name.

Below is the PHP code:

$lastname = 'Doe';

$client = new SoapClient("http://10.0.0.0/test/ContactValidation.asmx?WSDL", array('trace' => 1, 'exceptions' => 0));

$params->lastname = $lastname;

$object = $client->validateContact($params);
$result = $object->validateContactResult;

echo "Request :<br>", htmlspecialchars($client->getLastRequest()), "<br><br>";
echo "Response :<br>", htmlspecialchars($client->
getLastResponse()), "<br><br>";

echo "Output from print_r(): ";
print_r($result);

I was able to request and get the response from it. The return will consist one or more results as in dataset. The response seems like the correct in XML (<id>200011479</id><lastname>Doe</lastname><firstname>Jane</firstname>.)

Request :

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://10.0.0.0/test/">
<SOAP-ENV:Body>
<ns1:validateContact>
<ns1:lastname>Doe</ns1:lastname>
</ns1:validateContact>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Response :

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<validateContactResponse xmlns="http://10.0.0.0/test/">
<validateContactResult>
<xs:schema id="ResultSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="ResultSet" msdata:IsDataSet="true">
<xs:complexType>
<xs:choice maxOccurs="unbounded">
<xs:element name="Result">
<xs:complexType>
<xs:sequence>
<xs:element name="id" type="xs:string" minOccurs="0" />
<xs:element name="lastname" type="xs:string" minOccurs="0" />
<xs:element name="firstname" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<ResultSet xmlns="">
<Result diffgr:id="Result1" msdata:rowOrder="0" diffgr:hasChanges="inserted">
<id>200011478</id>
<lastname>Doe</lastname>
<firstname>John</firstname>
</Result>
<Result diffgr:id="Result2" msdata:rowOrder="1" diffgr:hasChanges="inserted">
<id>200011479</id>
<lastname>Doe</lastname>
<firstname>Jane</firstname>
</Result>
</ResultSet>
</diffgr:diffgram>
</validateContactResult>
</validateContactResponse>
</soap:Body>
</soap:Envelope>

I was looking for something similar like this when using print_r() and trying to see each key and element of the object.

[Just an example]
stdClass Object (
[Result] => stdClass Object (
[id] => 200011478
[lastname] => Doe
[firstname] => John
)
[Result] => stdClass Object (
[id] => 200011479
[lastname] => Doe
[firstname] => Jane
)
)

Instead, the output was presented as one whole string:

Output from print_r():

stdClass Object (
[schema] => [any] =>
200011478DoeJohn200011479DoeJane
)

Have done some research and studied it on php.net. Still, couldn't figure out what went wrong and couldn't read each value individually like <?=$result->lastname?>. Is there anything that I missed? (I have searched the site and still "stuck". Pardon me if I overlooked.) Any insight would be greatly appreciated! 🙂

    You say the output is

    200011478DoeJohn200011479DoeJane 

    It's probably

    <ResultSet xmlns="">
    <Result diffgr:id="Result1" msdata:rowOrder="0" diffgr:hasChanges="inserted">
    <id>200011478</id>
    <lastname>Doe</lastname>
    <firstname>John</firstname>
    </Result>
    <Result diffgr:id="Result2" msdata:rowOrder="1" diffgr:hasChanges="inserted">
    <id>200011479</id>
    <lastname>Doe</lastname>
    <firstname>Jane</firstname>
    </Result>
    </ResultSet>

    but in the absence of htmlspecialchars or a Content-Type of text/xml, it's being rendered as HTML and so non-HTML tags are being ignored.

    This would imply that you're not making any attempt to process the SOAP response's payload. I don't see you doing any overriding of __doRequest, so maybe that has something to do with it.

      Thanks for the suggestion.
      I used the example on php.net (http://www.php.net/manual/en/function.soap-soapclient-dorequest.php) as reference and I can't seem to get __doRequest worked out.
      In the meatime, I tried to use the same php code to consume a different web service which will produce the response with only one set of result and without the wsdl definition. For instance:

      Response :

      <?xml version="1.0" encoding="utf-8"?>
      <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <soap:Body>
      <validateContactResponse xmlns="http://10.0.0.0/test/">
      <validateContactResult>
      <id>200011478</id>
      <lastname>Doe</lastname>
      <firstname>John</firstname>
      <errorCode>0</errorCode>
      </validateContactResult>
      </validateContactResponse>
      </soap:Body>
      </soap:Envelope>

      In this case, I have no problem to read the data like this:

      <?=$result->id ?>
      <?=$result->lastname ?>
      <?=$result->firstname ?>
      <?=$result->errorCode ?>

      Here is what the output looks like from print_r():

      stdClass Object (
      [id] => 200011478
      [lastname] => Doe
      [firstname] => John
      [errorCode] => 0
      )

      Could it be that wsdl definition part affects the SOAP payload and causes it need a different way to get some sort of notation like this or present values in a format that shows keys and elements for the object? Please advise.

        Hi:
        What's inside that WSDL document your client are targeting?
        To help you out, I need to check those <binding>, <message>,
        <part> and even <types> of WSDL elements of it.
        Also, did you ever try classmap option ?

          Hi Qsan,

          What's inside that WSDL document your client are targeting?

          I'm sorry that I'm not quite certain about the question. Could you please kindly explain a bit more.

          To help you out, I need to check those <binding>, <message>,
          <part> and even <types> of WSDL elements of it.

          Please see attached file for the WSDL document. (Just a note, web service is in .NET not PHP.)

          Also, did you ever try classmap option ?

          Yes, I did. No luck as well.

          PHP code:

          $client = new SoapClient("http://10.0.0.0/test/ContactValidation.asmx?WSDL", array('classmap' => array('id'=>id, 'lastname'=>lastname, 'firstname'=>firstname, 'errorCode'=>errorCode)));

          $params->lastname = $lastname;

          $object = $client->validateContact($params);
          $result = $object->validateContactResult;

          var_dump($result);

          Same Output:

          object(stdClass)#5 (2)
          {
          ["schema"]=> string() ""
          ["any"]=> string() "200011478DoeJohn0200011479DoeJane0"
          }

          I'm clueless. 🙁 Do you see what went wrong? Or is there anything missing?

          Thanks for helping!

            OK, I have got some clues form the wsdl.txt you provided.

            Before I could identify the possible cause, a test is needed:

            use the same soapclient code listed in your post but take out classmap option and add trace option back, then dump the reponse like below:

            $result = $object->validateContactResult;

            var_dump($result);
            echo $client->__getLastResponse(); // do not use htmlspecialchars() here;

            then grap the output from two statements above in the "Source"of generated html page and post that output back here.

            BTW, the way you use classmap option is different to the way I used it. Yet, I do not think it is related to your current problem, which, I thought, is deeper than script level yet could be walked-around on script level.

            OK, I will help as much as I could...

              I put the trace option back and here is the results:

              Output from var_dump():

              object(stdClass)#4 (2) { ["schema"]=> string() "" ["any"]=> string() "200011478DoeJohn0200011479DoeJane0" }

              Output from $client->__getLastResponse():

              200011478DoeJohn0200011479DoeJane0

              Thanks!

                OK, Bee:
                Though the output is somehow different to what I expected. Yet I think the cause of the problem is as such:
                here is the segment from the WSDL document you provided:

                        <s:element name="validateContactResponse">
                            <s:complexType>
                                <s:sequence>
                                    <s:element maxOccurs="1" minOccurs="0" name="validateContactResult">
                                        <s:complexType>
                                            <s:sequence>
                                                <s:element ref="s:schema"/>
                                                <s:any/>
                                            </s:sequence>
                                        </s:complexType>
                                    </s:element>
                                </s:sequence>
                            </s:complexType>
                        </s:element>

                this tells SoapClient class, implementation of which is based on libxml2 library, to expects the structure of response like below:
                <validateContactResponse>
                <validateContactResult>
                [the contents of <schema/>] <-- character stream of an instance of XML Shema
                [the contents of <any/>] <-- character stream of any kind of well-formed XML contents
                </validateContactResult>
                </validateContactResponse>

                the segment from the output of __getLastResponse() call on your past posting
                shows exactly what it turned out:

                Bee wrote:

                <validateContactResponse xmlns="http://10.0.0.0/test/">
                <validateContactResult>
                <xs:schema id="ResultSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
                <xs:element name="ResultSet" msdata:IsDataSet="true">
                <xs:complexType>
                <xs:choice maxOccurs="unbounded">
                <xs:element name="Result">
                <xs:complexType>
                <xs:sequence>
                <xs:element name="id" type="xs:string" minOccurs="0" />
                <xs:element name="lastname" type="xs:string" minOccurs="0" />
                <xs:element name="firstname" type="xs:string" minOccurs="0" />
                </xs:sequence>
                </xs:complexType>
                </xs:element>
                </xs:choice>
                </xs:complexType>
                </xs:element>
                </xs:schema>
                <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
                <ResultSet xmlns="">
                <Result diffgr:id="Result1" msdata:rowOrder="0" diffgr:hasChanges="inserted">
                <id>200011478</id>
                <lastname>Doe</lastname>
                <firstname>John</firstname>
                </Result>
                <Result diffgr:id="Result2" msdata:rowOrder="1" diffgr:hasChanges="inserted">
                <id>200011479</id>
                <lastname>Doe</lastname>
                <firstname>Jane</firstname>
                </Result>
                </ResultSet>
                </diffgr:diffgram>
                </validateContactResult>
                </validateContactResponse>

                here <xs:schema>...</xs:schema> and <diffgr:diffgram>...</diffgr:diffgram> are two character streams mentioned above.

                now SoapClient has got these two streams, but how dose it deal with them and how does it present them on script level (also called userspace or userland) ?
                Because there is no additional clue provided to it, it just "grap" the CDATA sections from them and maps the result to a script level object with two string variables indicating the two elements, <schema/> and <any/>:

                Bee wrote:

                object(stdClass)#4 (2) {
                ["schema"]=> string() ""
                ["any"]=> string() "200011478DoeJohn0200011479DoeJane0"
                }

                OK, that's the cause I suspect.

                To solve the problem to get the data you want, you may try SoapVar and/or SoapParam classes, both of which, I guess, are designed or could be used for this kind of situation, to provide additional clues to SoapClient class. Yet the PHP online documents say little about them. classmap option could also be helpful.

                The other possible way is to use SimpleXML, a PHP5 built-in feature, to digest the SOAP response like this:
                $xml = simplexml_load_string($client->__getLastResponse());
                Then use the really "simple" syntax or xpath calls to get the data. You may also try DOM if you need more than SimpleXML provides.

                All right. Wish these tips could help you out.

                  Thanks for the explanation, I think I have a much better understanding of the possible cause and will work on it from there.
                  Again, thanks so much, Qsan, for your guides, time and patience with me.

                    5 years later

                    Hi there!

                    I'm new to this forum an to PHP / SOAP.

                    I'm having exactly the same problem as Bee.

                    Any one knows the solution?

                    I spent 2 days searching the web for an answer with no luck.

                    Thanks in advance.

                      a month later

                      I would venture to guess if you did this

                      echo $results->schema->any;
                      

                      And the Viewed Source of the output
                      you will find that you are outputting an XML string.

                      If that is the case, I can probably help you further.

                        Write a Reply...