Trouble Parsing SOAP response in PHP using simplexml - php

I'm using cURL to POST a SOAP request. The response is as follows:
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:To>http://www.w3.org/2005/08/addressing/anonymous</wsa:To>
<wsa:Action>http://www.csapi.org/schema/parlayx/common/v3_1/TerminalLocationPort/getLocationForGroupResponse</wsa:Action>
</env:Header>
<env:Body>
<ns2:getLocationForGroupResponse xmlns:ns2="http://www.csapi.org/schema/parlayx/terminal_location/v3_1/local">
<ns2:result>
<address>234983</address>
<reportStatus>Retrieved</reportStatus>
<currentLocation>
<latitude>12.5665</latitude>
<longitude>43.7708</longitude>
<timestamp>2012-01-03T17:06:16.805+01:30</timestamp>
</currentLocation>
</ns2:result>
<ns2:result>
<address>423903</address>
<reportStatus>Retrieved</reportStatus>
<currentLocation>
<latitude>12.2165</latitude>
<longitude>43.6518</longitude>
<timestamp>2012-01-03T17:06:16.824+01:30</timestamp>
</currentLocation>
</ns2:result>
</ns2:getLocationForGroupResponse>
</env:Body>
</env:Envelope>
I use this to decode:
$err = curl_error($soap_do);
$result = curl_exec($soap_do);
$xml = simplexml_load_string($result);
$ns = $xml->getNamespaces(true);
$soap = $xml->children($ns['env']);
$getaddressresponse = $soap->body->children($ns['ns2']);
foreach ($getaddressresponse->children() as $item) {
echo (string) $item->address . '<br />';
}
I'm having trouble decoding this with SimpleXML. This link seems most relevant to my situation but I'm unable to apply it to my case as the simpleXML element just
Warning: SimpleXMLElement::children() [simplexmlelement.children]: Node no longer exists in C:\.php on line 33 /*(line with the for each statement)*/
Any suggestions?
UPDATE:
If the server responds with the following error, how would I detect it..?
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:To>http://www.w3.org/2005/08/addressing/anonymous</wsa:To>
<wsa:Action>http://www.w3.org/2005/08/addressing/fault</wsa:Action>
</env:Header>
<env:Body>
<env:Fault>
<faultcode>env:Server</faultcode>
<faultstring>Service Exception</faultstring>
<detail>
<ns1:ServiceException xmlns:ns1="http://www.csapi.org/schema/parlayx/common/v3_1" xmlns:ns2="http://www.csapi.org/schema/parlayx/terminal_location/v3_1/local">
<messageId>SVC004</messageId>
<text>Trip not Found for this MSISDN</text>
</ns1:ServiceException>
</detail>
</env:Fault>
</env:Body>
</env:Envelope>

Variable and property names are case sensitive and while I was testing it, it turned out there's other stuff as well. The following works:
$soap = $xml->children($ns['env']);
$getaddressresponse = $soap->Body->children($ns['ns2']);
foreach ($getaddressresponse->getLocationForGroupResponse->children($ns['ns2']) as $item)
{
$item = $item->children();
echo $item->address . '<br />';
}
To answer the updated question:
$fault = $soap->Body->children($ns['env']);
if (isset($fault->Fault))
{
// Handle error
}

Related

Parsing a SOAP response

I have been spending hours trying to parse a SOAP response that I have no control over. I have tried numerous methods I found on SO with no luck.
Here is the response body I get from edge browser:
<?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:gXMLQueryResponse xmlns:ns1="urn:com-photomask-feconnect-IFeConnect" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<return xsi:type="xsd:string"><?xml version = &apos;1.0&apos; encoding = &apos;UTF-8&apos;?>
<ROWSET>
<ROW num="1">
<CUSTOMER_NAME>HITACHI</CUSTOMER_NAME>
</ROW>
</ROWSET>
</return>
</ns1:gXMLQueryResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
I'm trying to get the CUSTOMER_NAME value.
Here is the code I am using:
$client = new SoapClient($urla, array('trace' => 1));
try {
$result = $client->__soapCall("gXMLQuery", $params);
$response = ($client->__getLastResponse());
$xml = simplexml_load_string($response);
$rows = $xml->children('SOAP-ENV', true)->Body->children('ns1', true)->gXMLQueryResponse->return->ROWSET->ROW;
foreach ($rows as $row)
{
$customer = $row->CUSTOMER_NAME;
echo $customer;
}
} catch (SoapFault $e) {
}
return is a string, you need to parse it first before you can access it using SimpleXML.
First you need to decode the string using html_entity_decode, after that you can load the decoded string with simplexml_load_string:
$return = $xml->children('SOAP-ENV', true)->Body->children('ns1', true)->gXMLQueryResponse->return;
$decodedReturn = html_entity_decode($return, ENT_QUOTES | ENT_XML1, 'UTF-8');
$rowset = simplexml_load_string($decodedReturn);
echo $rowset->ROW->CUSTOMER_NAME;

Extract value from xml tag

I´m trying to extract the RecordID = "1014276" from a tag
I tried with :
$result = curl_exec($ch);
curl_close($ch);
$xml2 = simplexml_load_string($result);
echo $latitude = (string) $xml2['RecordID'];
This is the XML response:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Body>
<ns1:createDataResponse xmlns:ns1="http://3e.pl/ADInterface">
<StandardResponse RecordID="1014276" xmlns="http://3e.pl/ADInterface"/>
</ns1:createDataResponse>
</soap:Body>
</soap:Envelope>
This involves a bit more than just accessing the attribute, first you have to select the correct element. Using XPath is the most comment way in this sort of structure.
As this has a default namespace defined for the data, you will need to register this with the SimpleXMLElement first (using $xml2->registerXPathNamespace("ns1","http://3e.pl/ADInterface");.
You can then find the element using the XPAth expression //ns1:StandardResponse. As the xpath() method returns a list of found elements, use [0] to just extract the first match. You should then be able to extract the attribute as in your code using the resultant element...
$xml2 = simplexml_load_string($result);
$xml2->registerXPathNamespace("ns1","http://3e.pl/ADInterface");
$response = $xml2->xpath("//ns1:StandardResponse")[0];
echo (string) $response['RecordID'];
You can apporach this as
$xml = '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Body>
<ns1:createDataResponse xmlns:ns1="http://3e.pl/ADInterface">
<StandardResponse RecordID="1014276" xmlns="http://3e.pl/ADInterface"/>
</ns1:createDataResponse>
</soap:Body>
</soap:Envelope>';
$p = xml_parser_create();
xml_parse_into_struct($p, $xml, $values, $index);
xml_parser_free($p);
echo $values[3]['attributes']['RECORDID'];

Parsing an XML response with namespaces

I'm getting an XML response that I cannot parse. Here's the thing:
<?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>
<soap:Fault>
<faultcode>soap:Client</faultcode>
<faultstring>Exception occurred</faultstring>
<faultactor>https://services.lso.com/partnershippingservices/v1_5/PricingService.asmx</faultactor>
<detail>
<webServiceException xmlns="https://services.lso.com/WebServiceException/v1">
<code>600121</code>
<action>To zip code is outside of service area.</action>
</webServiceException>
</detail>
</soap:Fault>
</soap:Body>
</soap:Envelope>
It's the response when an error occurs. What I want to get is the values of both code and action.
I know how to handle the response when the request was correctly processed, but I can't do much when an error is returned.
Just to give you an idea, this is what I'm doing with the response I can handle:
$responseRate = simplexml_load_string($xmlRateResponse);
$getTotalCharge = $responseRate->children('http://schemas.xmlsoap.org/soap/envelope/')
->Body->children()
->EstimatePriceResponse;
$totalCharge = (float)$getTotalCharge->EstimatePriceResult->TotalCharge;
echo $totalCharge;
With this, I can display the rate that is returned.
Any help will be appreciated. Thanks.
Alright, here's a solution.
$xmlResponse = new SimpleXMLElement($errorResponse);
$xmlResponse->registerXPathNamespace('soap','http://schemas.xmlsoap.org/soap/envelope/');
$result=$xmlResponse->xpath('//soap:Fault');
foreach ($result as $body) {
echo $body->detail->webServiceException->code . "<br>";
echo $body->detail->webServiceException->action . "<br>";
}
This is going to return "600121" and "To zip code is outside of service area.", which is what I want.

Parsing XML SOAP response in PHP

I have been trying to parse an XML SOAP response in PHP but I continue to get errors. I cannot figure out why these errors are occuring.
Response from the server, stored in $response as a string (with sensitive data removed):
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<h:ServerVersionInfo MajorVersion="15" MinorVersion="20" MajorBuildNumber="323" MinorBuildNumber="19" Version="V2017_10_09" xmlns:h="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
</s:Header>
<s:Body>
<m:GetAttachmentResponse xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
<m:ResponseMessages>
<m:GetAttachmentResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError</m:ResponseCode>
<m:Attachments>
<t:FileAttachment>
<t:AttachmentId Id="id number"/>
<t:Name>message-footer.txt</t:Name>
<t:ContentType>text/plain</t:ContentType>
<t:ContentId>contentid.prod.outlook.com</t:ContentId>
<t:Content>file contents</t:Content>
</t:FileAttachment>
</m:Attachments>
</m:GetAttachmentResponseMessage>
</m:ResponseMessages>
</m:GetAttachmentResponse>
</s:Body>
</s:Envelope>
My code:
$data = simplexml_load_string($response);
$fileData = $data
->children('s:', true)->Body
->children('m:', true)->GetAttachmentResponse->ResponseMessages->GetAttachmentResponseMessage->Attachments
->children('t:', true)->FileAttachment;
I need to be able to get the file name, content type, and content. I continue to get the following error: Node no longer exists (on line 4 here).
For reference, I have been following this guide: https://joshtronic.com/2014/07/13/parsing-soap-responses-with-simplexml/
Any help is greatly appreciated.
I don't know how to read such a complex XML file with simplexml, but I know that DOMDocument works very well for it.
<?php
$source = file_get_contents('file.xml');
$dom = new DOMDocument("1.0", "UTF-8");
$dom->preserveWhiteSpace = false;
$dom->loadXml($source);
$xpath = new DOMXPath($dom);
$xpath->registerNamespace("s", "http://schemas.xmlsoap.org/soap/envelope/");
$xpath->registerNamespace("m", "http://schemas.microsoft.com/exchange/services/2006/messages");
$xpath->registerNamespace("xsd", "http://www.w3.org/2001/XMLSchema");
$xpath->registerNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
$xpath->registerNamespace("t", "http://schemas.microsoft.com/exchange/services/2006/types");
$fileAttachments = $xpath->query('//m:GetAttachmentResponseMessage/m:Attachments/t:FileAttachment');
/* #var DOMElement $fileAttachment */
foreach ($fileAttachments as $fileAttachment) {
echo 'Name: ' . $xpath->query('t:Name', $fileAttachment)->item(0)->nodeValue . "\n";
echo 'ContentType: ' . $xpath->query('t:ContentType', $fileAttachment)->item(0)->nodeValue . "\n";
echo 'Content: ' . $xpath->query('t:Content', $fileAttachment)->item(0)->nodeValue . "\n";
}

SOAP response - parsing xml in php, how to access?

I have response from webservice:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://tempuri.org/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns1:H1 xsi:type="ns1:H1">
<BOGUS>
<time>1411967345</time>
<status>1</status>
<speed>0</speed>
</BOGUS>
<BOGUS>
<time>1411964888</time>
<status>10</status>
<speed>0</speed>
</BOGUS>
</ns1:H1>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
How can I access to element time or status in BOGUS[0] or BOGUS[1]?
I tried this:
$soap = simplexml_load_string($str);
$response = $soap->children('http://schemas.xmlsoap.org/soap/envelope/')->Body->children('http://tempuri.org/')->H1;
$time = $response->BOGUS[1]->time;
echo $time;
, but it's not working. Returns: Notice: Trying to get property of non-object
tempuri.org is right. I pasted xml response on: xmlgrid.net and got correct tree.
I'd recommandate to use Zend Soap Client for PHP. There u can do like this:
$client = new Zend_Soap_Client("MyService.wsdl");
$result = $client->yourMethod(<YouParameters ...>);
echo $result->H1->BOGUS[1]->time;
See:
http://framework.zend.com/manual/1.12/de/zend.soap.client.html
You can do it by loops as you are getting array in return
foreach ($response as $res)
{
$time = $res->BOGUS[1]->time;
echo $time;
}

Categories