Parsing XML SOAP response in PHP - 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";
}

Related

Parsing xml response from ebay getsellerlist with php

I am trying to parse XML with PHP. The XML is a response from ebay getsellerlist api, and is structured like so:
<!--?xml version="1.0" encoding="UTF-8"?-->
<getsellerlistresponse xmlns="urn:ebay:apis:eBLBaseComponents">
<timestamp>2016-08-11T14:17:39.869Z</timestamp>
<ack>Success</ack>
<version>967</version>
<build>E967_CORE_APISELLING_17965876_R1</build>
<itemarray>
<item>
<itemid>itemid1</itemid>
<listingdetails>
<viewitemurl>itemurl1</viewitemurl>
</listingdetails>
<primarycategory>
<categoryid>categoryid1</categoryid>
<categoryname>categoryname1</categoryname>
</primarycategory>
<title>title1</title>
<picturedetails>
<galleryurl>url1</galleryurl>
<photodisplay>thumbnail1</pictureurl>
<pictureurl>picture1</pictureurl>
</picturedetails>
</item>
</itemarray>
</getsellerlistresponse>
My php is as follows:
<?
$xml = '<!--?xml version="1.0" encoding="UTF-8"?--><getsellerlistresponse xmlns="urn:ebay:apis:eBLBaseComponents"><timestamp>2016-08-11T14:17:39.869Z</timestamp><ack>Success</ack><version>967</version><build>E967_CORE_APISELLING_17965876_R1</build><itemarray><item><itemid>itemid1</itemid><listingdetails><viewitemurl>itemurl1</viewitemurl></listingdetails><primarycategory><categoryid>categoryid1</categoryid><categoryname>categoryname1</categoryname></primarycategory><title>title1</title><picturedetails><galleryurl>url1</galleryurl><photodisplay>thumbnail1</pictureurl><pictureurl>picture1</pictureurl></picturedetails></item><item><itemid>itemid2</itemid><listingdetails><viewitemurl>itemurl2</viewitemurl></listingdetails><primarycategory><categoryid>categoryid2</categoryid><categoryname>categoryname2</categoryname></primarycategory><title>title1</title><picturedetails><galleryurl>url2</galleryurl><photodisplay>thumbnail2</pictureurl><pictureurl>picture2</pictureurl></picturedetails></item></itemarray></getsellerlistresponse>';
$dom = new DOMDocument();
$dom->loadXML($xml);
$title_nodes = $dom->getElementsByTagName('title');
$titles = array();
foreach ($title_nodes as $node) {
$titles[] = $node->nodeValue;
echo $node->nodeValue;
}
echo $titles[0];
echo count($titles);
?>
When I run it, I get a blank page, no errors, nothing.
If I check $titles length using count(), it comes back as zero.
For some reason it is not getting the title node (or any other nodes) and I can't figure out how to parse the xml string with php and get the node values.
Any help most appreciated, if the question is vague or lacking detail, please let me know and I will correct it.
The XML isn't valid:
Unable to parse any XML input. org.jdom2.input.JDOMParseException: Error on line 2: The element type "photodisplay" must be terminated by the matching end-tag "".
And that's only after you remove the comments in your XML declaration:
<!--?xml version="1.0" encoding="UTF-8"?-->
shoud be
<?xml version="1.0" encoding="UTF-8"?>
Working demo:
<?php
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<getsellerlistresponse xmlns="urn:ebay:apis:eBLBaseComponents">
<timestamp>2016-08-11T14:17:39.869Z</timestamp>
<ack>Success</ack>
<version>967</version>
<build>E967_CORE_APISELLING_17965876_R1</build>
<itemarray>
<item>
<itemid>itemid1</itemid>
<listingdetails>
<viewitemurl>itemurl1</viewitemurl>
</listingdetails>
<primarycategory>
<categoryid>categoryid1</categoryid>
<categoryname>categoryname1</categoryname>
</primarycategory>
<title>title1</title>
<picturedetails>
<galleryurl>url1</galleryurl>
<photodisplay>thumbnail1</photodisplay>
<pictureurl>picture1</pictureurl>
</picturedetails>
</item>
</itemarray>
</getsellerlistresponse>';
$dom = new DOMDocument();
$dom->loadXML($xml);
$title_nodes = $dom->getElementsByTagName('title');
$titles = array();
foreach ($title_nodes as $node) {
$titles[] = $node->nodeValue;
echo $node->nodeValue;
}
echo $titles[0];
echo count($titles);

how to extract SOAP response in PHP

I have a SOAP response as follows:
<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope" xmlns="">
<faultcode>stuff</faultcode>
<faultstring>stuff</faultstring>
<detail>
<ns2:Exception xmlns:ns2="http://blah.com/">
<message>stuff</message>
</ns2:Exception>
</detail>
</S:Fault>
</S:Body>
</S:Envelope>
I need to extract faultcode, faultstring, and message.
I have tried SimpleXML_load_string, SimpleXMLElement, DOMDocument, registerXPathNamespace and json_decode but can't seem to get the exact procedure correct because I get errors instead of results. Thanks in advance.
Latest attempt:
$xmle1 = SimpleXML_load_string(curl_exec($ch));
if (curl_errno($ch)) {
print "curl error: [" . curl_error($ch) . "]";
} else {
$xmle1->registerXPathNamespace('thing1', 'http://blah.com/');
foreach ($xml->xpath('//thing1:message') as $item) {
echo (string) $item;
}
<?php
$string = <<<XML
<?xml version="1.0" ?>
<S:Envelope
xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<S:Fault
xmlns:ns4="http://www.w3.org/2003/05/soap-envelope"
xmlns="">
<faultcode>stuff</faultcode>
<faultstring>stuff</faultstring>
<detail>
<ns2:Exception
xmlns:ns2="http://blah.com/">
<message>stuff</message>
</ns2:Exception>
</detail>
</S:Fault>
</S:Body>
</S:Envelope>
XML;
$_DomObject = new DOMDocument;
$_DomObject->loadXML($string);
if (!$_DomObject) {
echo 'Error while parsing the document';
exit;
}
$s = simplexml_import_dom($_DomObject);
foreach(['faultcode','faultstring','message'] as $tag){
echo $tag.' => '.$_DomObject->getElementsByTagName($tag)[0]->textContent.'<br/>';
}
?>
outputs
faultcode => stuff
faultstring => stuff
message => stuff
you might want to write a class to parse the XML string and build an nice Fault object with methods for easier access after you parse it.

PHP - Format XML Output

I'm generating some XML data in response to an HTTP POST request. I'm setting the MIME
header('Content-type: text/xml');
and everything is working well so far.
I'm generating the xml response as follows:
$response = '<?xml version="1.0" encoding="utf-8"?>';
$response .= '<error>';
$response .= '<description>'.$error.'</description>';
$response .= '</error>';
echo $response;
I would now like the format the XML so that instead of seeing this response:
<?xml version="1.0" encoding="utf-8"?><error><description>Login Error: No Username Supplied</description></error>
they see this response:
<?xml version="1.0" encoding="utf-8"?>
<error>
<description>Login Error: No Username Supplied</description>
</error>
I haven't worked with XML output with PHP before so not sure if there's a built in method for doing a "pretty print" type function on the output?
Use the DOM library and set the formatOutput property to true
$doc = new DOMDocument('1.0', 'utf-8');
$doc->formatOutput = true;
$root = $doc->createElement('error');
$doc->appendChild($root);
$desc = $doc->createElement('description', $error);
$root->appendChild($desc);
echo $doc->saveXML();
Demo ~ https://eval.in/461384

Trouble Parsing SOAP response in PHP using simplexml

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
}

XML file to PHP array (w/attributes)

i haven't really worked with xml files before, but now i'm trying to get an xml file into a php array or object.
the xml file looks like this: (it's for translating a web app)
<?xml version="1.0" ?>
<content language="de">
<string name="login">Login</string>
<string name="username">Benutzername</string>
<string name="password">Passwort</string>
</content>
i tried the following:
$xml = new SimpleXMLElement("de.xml", 0, 1);
print_r($xml);
unfortunately, the values of the 'name' attribute are for some reason not in the php object. i'm looking for a way that allows me to retrieve the xml values by the name attribute.
for instance:
$xml['username'] //returns "Benutzername"
how can this be done?
appreciate your help :) cheers!
This one should explain the function to you:
<?php
$xml = simplexml_load_file('de.xml');
foreach($xml->string as $string) {
echo 'attributes: '. $string->attributes() .'<br />';
}
?>
The attributes() method from SimpleXMLElement class will help you - http://de.php.net/manual/en/simplexmlelement.attributes.php
$xmlStr = <<<XML
<?xml version="1.0" ?>
<content language="de">
<string name="login">Login</string>
<string name="username">Benutzername</string>
<string name="password">Passwort</string>
</content>
XML;
$doc = new DomDocument();
$doc->loadXML($xmlStr);
$strings = $doc->getElementsByTagName('string');
foreach ($strings as $node) {
echo $node->getAttribute('name') . ' = ' . $node->nodeValue . PHP_EOL;
}
You can use an xpath expression to get the element with the name you are looking for:
(string)current($xml->xpath('/content/string[#name="username"]'))

Categories