I haven't done any xml projects, so I'm not quite sure what to do with this data...
I'm using curl to make a request to salesforce, and they give me back a response that I need to parse. I want to use simplexml. Here's part of the response:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="urn:partner.soap.sforce.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<loginResponse>
<result>
<metadataServerUrl>
https://na6-api.salesforce.com/services/Soap/m/18.0/
</metadataServerUrl>
<passwordExpired>
false
</passwordExpired>
<sandbox>
false
</sandbox>
<serverUrl>
https://na6-api.salesforce.com/services/Soap/u/18.0/
</serverUrl>
<sessionId>
!AQ4AQLtDIqY.
</sessionId>
<userId>
</userId>
<userInfo>
<accessibilityMode>
false
</accessibilityMode>
<currencySymbol>
$
</currencySymbol>
<orgDefaultCurrencyIsoCode>
USD
</orgDefaultCurrencyIsoCode>
<orgDisallowHtmlAttachments>
false
</orgDisallowHtmlAttachments>
<orgHasPersonAccounts>
false
</orgHasPersonAccounts>
<organizationId>
</organizationId>
<organizationMultiCurrency>
false
</organizationMultiCurrency>
<organizationName>
Ox
</organizationName>
<profileId>
sdfgsdfg
</profileId>
<roleId>
sdfgsdfg
</roleId>
<userDefaultCurrencyIsoCode xsi:nil="true"/>
<userEmail>
####gmail.com
</userEmail>
<userFullName>
### ###
</userFullName>
<userId>
asdfasdf
</userId>
<userLanguage>
en_US
</userLanguage>
<userLocale>
en_US
</userLocale>
<userName>
asdfasdf#gmail.com
</userName>
<userTimeZone>
America/Chicago
</userTimeZone>
<userType>
Standard
</userType>
<userUiSkin>
Theme3
</userUiSkin>
</userInfo>
</result>
</loginResponse>
</soapenv:Body>
</soapenv:Envelope>
Anyway, I expected to feed that stuff (we'll call it data) into
$results = simplexml_load_string($data);
var_dump($results);
And that would give me all the data back... and then to access specific parts, it would be $results->body->loginResponse->blah->blah...
But It's not giving me that, it's not really giving me anything back, just an empty simple xml object...
So one website made me think I might need an XSLT to read this correctly.
Or something else made me think it's because I don't have at the top.
Help!
You can use SimpleXML but it's not quite as simple as you hope due to the use of namespaces (e.g. soapenv). Look into using SimpleXMLElement::children like:
$sxe = new SimpleXMLElement($data);
$login_response = $sxe->children('soapenv', TRUE)->Body->children('', TRUE)->loginResponse->result;
// Now that we have the <loginResponse> lets take a look at an item within it
echo $login_response->userInfo->userEmail;
Finally, and importantly, have you had a look at salesforce's tools & examples?
SimpleXML needs a special treatment for namespaced XML (ref.)
Mate,
Name spaces usually require you to make a call using children to return the namespaced elements. I would recommend using a soap client like php soapclient, but since I've never used it before there is one other possible option.
$results = simplexml_load_string($data);
$xml = $results->children('http://schemas.xmlsoap.org/soap/envelope/');
var_dump($xml);
I believe that's how it works.
For what it's worth, you may find you have an easier time using a PHP SoapClient for this task. O'Reilly has a good tutorial on PHP SOAP.
Also checkout the PHP Toolkit for making SOAP calls to Salesforce.com
I try to follow the syntax by salathe. But children('soapenv', TRUE) doens't work for me, Jason's children('http://schemas.xmlsoap.org/soap/envelope/') work.
Therefore, to read the field value CreatedDate in Salesforce Outbound Message, I need following code:
$rcXML->children('http://schemas.xmlsoap.org/soap/envelope/')->Body->children('http://soap.sforce.com/2005/09/outbound')->notifications->Notification->sObject->children('urn:sobject.enterprise.soap.sforce.com')->CreatedDate
To help you understand how it work, I write a post with sames code and xml which shall be easier to understand.
http://amigotechnotes.wordpress.com/2013/11/16/parse-xml-with-namespace-by-simplexml-in-php/
Parsing soap responses with SimpleXML has a brilliant and concise example of multi-namespace XML parsing.
For anyone wanting to get at the RateResponse from the UPS Rating API, here's how :
// $client is your SoapClient object
$dom = new DOMDocument;
$dom->loadXML($client->__getLastResponse());
$xml = simplexml_load_string($dom->saveXML(), NULL, NULL, 'http://schemas.xmlsoap.org/soap/envelope/');
$RateResponse = $xml->xpath('/soapenv:Envelope/soapenv:Body')[0]->children('rate', true)->RateResponse;
foreach($RateResponse->RatedShipment as $RatedShipment) {
print_r((array)$RatedShipment);
}
For SAOP request, we can parse easily with a short code by replacing the SOAP-ENV: tag with blank
$response = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="urn:partner.soap.sforce.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>';
$response = html_entity_decode($response);
$response = str_replace(['soapenv:', 'ns1:', ':ns1', 'SOAP-ENV:'], ['', '', '', ''], $response);
$objXmlData = simplexml_load_string($response);
Related
I am struggling to get to grips with creating the "xml" data for a PHP based SOAP client. I need to produce something like the following:
<SOAP-ENV:Body>
<ns1:check_stock_level>
<ns1:api_credentials>
<ns1:username>*****</ns1:username>
<ns1:password>***</ns1:password>
</ns1:api_credentials>
<productsku>ABC-123</productsku>
</ns1:check_stock_level>
</SOAP-ENV:Body>
I can create the authorisation section, but my code fails to create the productsku - the code looks like this:
$client = new SoapClient("https://www.example.net/wh_api.asmx?WSDL",array("trace"=> 1, "exceptions" => 0));
$auth = array ('api_credentials' => array ('username'=>'******', 'password'=>'******'));
$sku = array('productsku'=>'ABC-123');
$result = $client->check_stock_level($auth, $sku);
which produces this:
<SOAP-ENV:Body>
<ns1:check_stock_level>
<ns1:api_credentials>
<ns1:username>*****</ns1:username>
<ns1:password>***</ns1:password>
</ns1:api_credentials>
</ns1:check_stock_level>
<param1>
<item>
<key>product_sku</key>
<value>ABC-123</value>
</item>
</param1>
</SOAP-ENV:Body>
Where the productsku is outside of the <check_stock_level> tag set and is surrounded by extra tags.
Most examples I can find on SOAP use NuSOAP but I want to use the native pHP SOAP functionality. Can anyone give me any pointers?
Resolved it myself, the two arrays needed to be combined - by having them as separate arrays, the productsku data was moved outside of the tag set.
After breaking my head on a wall for a whole day i just think i need some help for this.
I'm receiving the following answer from a soap call :
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<SearchBrochuresResponse xmlns="http://services.iceportal.com/service">
<SearchBrochuresResult>
<pageNumber>0</pageNumber>
<brochures>
<SearchBrochure>
<iceID>10427</iceID>
<city>Acapulco</city>
</SearchBrochure>
</brochures>
</SearchBrochuresResult>
</SearchBrochuresResponse>
</soap:Body>
</soap:Envelope>
I tried all i could find on the subject on stackoverflow and all the other sources i found, but i couldn't access to the iceID, basically my goal is to get into a php variable the value of the iceID node.
Thanks a lot for your help.
Assume your xml data is in the variable $data you could create a simple XML object from it, then access it's nodes in the following way (example to get iceID):
$xml = simplexml_load_string($data);
$iceID = (string)$xml->children('soap', true)
->Body->children()
->SearchBrochuresResponse
->SearchBrochuresResult
->brochures
->SearchBrochure
->iceID;
You could look into XPath, the technique used to navigate and select parts of an XML document.
Wikipedia on XPath
If you need more help please post a more specific question. What have you tried? Do you only need to extract that specific value?
How can I force my PHP SoapServer to send a JSON object as a response instead of an XML doc?
Thanks.
That is not SOAP, so no. It can incorporate a jsonstring in some xml node, that's about it. You may want just a REST server serving json.
You can bastardize it though, making it by definition NOT SOAP, but some weird hybrid:
<?php
class ThisIsNotASoapServer extends SoapServer {
}
function test(){
//should have a return
//return range(1,9);
//but totally breaks it by:
echo json_encode(range(1,9));
//the exit here is needed
exit;
}
$server = new ThisIsNotASoapServer(null, array('uri' => 'http://test-uri/','soap_version' => 1));
$server->addFunction("test");
$server->handle('<?xml version="1.0"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<m:Test xmlns:m="Some-URI"/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>');
?>
... so, technically this is possible, but I suspect there is not a single client which understands this.
Take a look at http://www.sinatrarb.com its very easy to create a restful web service to return a json object.
depends on your requirements - SOAP is a xml request it doesnt mean the format for the return also needs to be SOAP (XML) you can easily post back a JSON string.
Maybe if you can provide more information we can help more?
I am having serious issues parsing this xml array using curl. I only need the click_id printed on each new row. Does someone have an example of how I can pull this. I am using curl and get the response below in the variable $result. I am using php.
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfClick xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://cakemarketing.com/api/1/">
<Click>
<click_id>7458165</click_id>
<request_session_id>7901644</request_session_id>
<click_date>2011-09-08T13:53:37.143</click_date>
<offer_id>10346</offer_id>
<advertiser_id>1050</advertiser_id>
<campaign_id>6527</campaign_id>
</Click>
<Click>
<click_id>7459318</click_id>
<request_session_id>7903011</request_session_id>
<click_date>2011-09-08T14:41:37.953</click_date>
<offer_id>10346</offer_id>
<advertiser_id>1050</advertiser_id>
<campaign_id>6527</campaign_id>
</Click>
The best way is to use XPath with the help of this class http://php.net/manual/en/class.domxpath.php
A more simple method is to use regex (but I discourage this approach)
I'm sending a SOAP request that looks like:
<SOAP-ENV:Body>
<api:GetOrder xsi:type="SOAP-ENC:Struct">
<api_orderId xsi:type="xsd:int">1234</api_orderId>
</api:GetOrder>
</SOAP-ENV:Body>
But needs to look like this (SoapUI generated):
<soapenv:Body>
<api:GetOrder>
<api:orderId>1234</api:orderId>
</api:GetOrder>
</soapenv:Body>
My PHP Code:
$client = $this->getConnection();
$soap_options = array('soapaction' => $config->getValue('soapaction_url') . 'GetOrder');
$obj = new stdClass();
$obj->api_orderId = 59698;
$results = $client->__soapCall('GetOrder', array(new SoapParam($obj, "api:GetOrder")), $soap_options);
2 questions really:
1) How can I remove the "xsi:type" from the request? (If I add xsi:type in to my SoapUI request, I get back a "400 Bad Request"
2) Instead of "api_orderId" I need to send "api:orderId", but I can't name an object with a colon, so do I have to pass the name and value as an array somehow?
Appreciate any help, thank you.
EDIT:
I wasn't able to figure out any other way to send these requests and I essentially ended up doing as Mr.K suggested below.
I wrote a custom class to extend SoapClient. Then overrode the __doRequest method to send my own custom SOAP request.
The only downside is that SOAP no longer returns me an array of objects, so I also had to parse the XML of the SOAP response.
Also I suspect that the performance of doing it this way is a bit slower, but I didn't notice it.
Try with Simple XML parsing, and create the new request as you like.
Read the tag values from Original request, assign those values to a new XML object using parsing. You can create string of XML message and load it as an XML object in PHP.
Just like get it from there, put it inside this..and Send!..