I'm guessing the NameSpaces are causing simplexml_load_string to not work, but I'm definitely not sure.
log.xml
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sns="http://soap.com/pbx">
<env:Body>
<sns:CDR>
<PrimaryCallID>02v7b7c16v#12.123.123.12</PrimaryCallID>
<CallID>d352f920#pbx</CallID>
<From>"SMITH JOHN " <sip:11234567890#sub.domain.com:5060;user=phone></From>
<To><sip:3216549870#111.111.111.111:5060;user=phone></To>
<Direction>O</Direction>
<Type>attendant</Type>
<RemoteParty />
<LocalParty />
<TrunkName />
... more xml...
</sns:CDR>
</env:Body>
</env:Envelope>
parse.php
<?php
$string = "log.xml";
$xml = simplexml_load_string($string);
print_r($xml);
?>
I'm getting nothing back from the print_r
What am I missing?
simplexml_load_string takes a string as an argument not a filename.
you're trying to load the string "log.xml" as a XML and that doesn't work
you can use this intead:
$filename = "log.xml";
$xml = simplexml_load_string(file_get_contents($filename));
print_r($xml);
Related
I'm receiving from an external web service an XML like this(notice the colons inside the tags)
XML
<?xml version='1.0' encoding='UTF-8'?>
<env:Envelope
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns0="http://webservice/CrsWSApi.wsdl/types/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>
<ns0:callwsapiResponseElement>
<ns0:result>
<ns0:object>BTS</ns0:object>
<ns0:receiver>BTSV45_ANSF_PROD-AKITT</ns0:receiver>
<ns0:sender>ANSFP</ns0:sender>
<ns0:data>
{"name":"Paolo", "cognome": Rossi, "data":"18/11/1983"}
</ns0:data>
<ns0:errormess xsi:nil="true"/>
<ns0:errorcode xsi:nil="true"/>
<ns0:status>1</ns0:status>
<ns0:sessionid>akit1</ns0:sessionid>
</ns0:result>
</ns0:callwsapiResponseElement>
</env:Body>
</env:Envelope>
if I use this function to parse it
PHP
$xml = simplexml_load_string($xml) or die("Error: Cannot create object");
I'm always receiving Error. If I remove the colons it works as expected. Is there a way to make this works without manipulating the colons before the xml parsing?
I want to avoid this manipulation
PHP
$xml = preg_replace(['/env:/','/:env(?!=)/','/ns0:/','/:ns0(?!=)/'], '', $myXMLData);
UPDATE
I already accepted a good answer that is reporting usefull links on how namespases are working in an xml environment, but I want to share another way to obtain the same result without parsing an xpath expression. We can you use the children method of simple_xml_loadstring specifiying the second parameter as a namespace.
fot the above code you can obtain the ns0:data content with this code(before you have to change the if statement as the accepted answer)
PHP
$xml = simplexml_load_string($response);
echo $xml
->children("env", true)
->Body
->children("ns0", true)
->callwsapiResponseElement
->result
->data;
// This will print
{"name":"Paolo", "cognome": Rossi, "data":"18/11/1983"}
For me it is very curious the return of simplexml_load_string (https://www.php.net/manual/en/function.simplexml-load-string.php):
This function may return Boolean false, but may also return a non-Boolean value which evaluates to false. Please read the section on Booleans for more information. Use the === operator for testing the return value of this function.
And indeed if you replace the or die:
<?php
$response = <<<XML
<?xml version='1.0' encoding='UTF-8'?>
<env:Envelope
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns0="http://webservice/CrsWSApi.wsdl/types/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>
<ns0:callwsapiResponseElement>
<ns0:result>
<ns0:object>BTS</ns0:object>
<ns0:receiver>BTSV45_ANSF_PROD-AKITT</ns0:receiver>
<ns0:sender>ANSFP</ns0:sender>
<ns0:data>
{"name":"Paolo", "cognome": Rossi, "data":"18/11/1983"}
</ns0:data>
<ns0:errormess xsi:nil="true"/>
<ns0:errorcode xsi:nil="true"/>
<ns0:status>1</ns0:status>
<ns0:sessionid>akit1</ns0:sessionid>
</ns0:result>
</ns0:callwsapiResponseElement>
</env:Body>
</env:Envelope>
XML;
$xml = simplexml_load_string($response);
if($xml===false){
die();
}
echo $xml->xpath("//*[local-name() = 'receiver']")[0];
Results:
BTSV45_ANSF_PROD-AKITT
You can then use the namespaces to find your data. This is a nice post Reference - How do I handle Namespaces (Tags and Attributes with a Colon in their Name) in SimpleXML?
SO,
I'm receiving the following SOAP response as a string:
<?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>
<GetListItemsResponse xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<GetListItemsResult>
<listitems xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema">
<rs:data ItemCount="3">
<z:row ows_DocIcon="jpg" ows_LinkFilename="18380014229851.jpg" ows_Modified="2016-10-08 17:27:40" ows_Editor="179440;#asdf" ows_Last_x0020_Modified="2;#2016-10-08 17:29:29" ows_ID="2" ows_Created_x0020_Date="2;#2016-10-08 17:27:40" ows_FileLeafRef="2;#18380014229851.jpg" />
<z:row ows_DocIcon="jpg" ows_LinkFilename="18380014229851_2.jpg" ows_Modified="2016-10-08 17:27:40" ows_Editor="179440;#asfd" ows_Last_x0020_Modified="3;#2016-10-08 17:29:29" ows_ID="3" ows_Created_x0020_Date="3;#2016-10-08 17:27:41" ows_FileLeafRef="3;#18380014229851_2.jpg" />
<z:row ows_DocIcon="jpg" ows_LinkFilename="18380014229851_3.jpg" ows_Modified="2016-10-08 17:27:40" ows_Editor="179440;#asdf" ows_Last_x0020_Modified="4;#2016-10-08 17:30:03" ows_ID="4" ows_Created_x0020_Date="4;#2016-10-08 17:27:41" ows_FileLeafRef="4;#18380014229851_3.jpg" />
</rs:data>
</listitems>
</GetListItemsResult>
</GetListItemsResponse>
</soap:Body>
</soap:Envelope>
I am attempting to get each of the "z:row" entries, but am struggling due to the namespaces (after some googling that's what i'm understanding them to be called).
Here is the code I am using:
$xml = simplexml_load_string($sp->soapClient->__last_response);
foreach($xml->GetListItemsResult as $item)
{
$ns_li = $item->children('uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882');
$ns_rs = $ns_li->children('urn:schemas-microsoft-com:rowset');
$ns_z = $nr_rs->children('#RowsetSchema');
echo $ns_z->row;
}
Right now I am getting no output from echo statement. What am I doing wrong?
You can use XPath expression to get specific part of XML document using various criteria. For example, to get z:row elements anywhere in the XML document you can simply do //z:row, after registering the prefix z :
$xml->registerXPathNamespace("z", "#RowsetSchema");
foreach($xml->xpath('//z:row') as $item)
{
echo $item["ows_LinkFilename"] ."\n";
}
eval.in demo
output :
18380014229851.jpg
18380014229851_2.jpg
18380014229851_3.jpg
I'm building xml with the SimpleXMLElement Object from PHP.
While doing so I encountered the following problem, which i can't solve:
I'm generating the root xml element like this:
$xml = new SimpleXMLElement("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
But i get a 2 XML headers when i do echo $xml->asXML(); like this:
<?xml version="1.0"?>
<xml version="1.0" encoding="UTF-8"></xml>
Which is obvioulsy wrong. But how can i fix this so i only get the
<xml version="1.0" encoding="UTF-8">
part?
You must also supply the surrounding tag.
For example:
$xml = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8" ?> <BASETAG />');
So I'm getting an xml file back from a soap service (of which I have no control over). It's returning back an xmlns which is causing simpleXML issues. I'm running a str_replace to get rid of that issue, however now simpleXML just returns an empty object. XML structure appears to be fine, no errors just an empty object.
$xmlString = $client->__getLastResponse();
$feed = str_replace(' xmlns="LMSWebservice"', '', $xmlString);
$sData= simplexml_load_string($feed);
print_r($sData);
Returns: SimpleXMLElement Object()
XML source before str replace is:
<?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>
<GetUserInternalIDByPersonalIDResponse xmlns="LMSWebservice">
<GetUserInternalIDByPersonalIDResult>
<Response xmlns="">
<Timestamp date="24/10/2013" time="04:27:37" />
<User>
<UserInternalID>4907</UserInternalID>
</User>
</Response>
</GetUserInternalIDByPersonalIDResult>
</GetUserInternalIDByPersonalIDResponse>
</soap:Body>
</soap:Envelope>
After str replace:
<?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>
<GetUserInternalIDByPersonalIDResponse>
<GetUserInternalIDByPersonalIDResult>
<Response xmlns="">
<Timestamp date="24/10/2013" time="04:27:37" />
<User>
<UserInternalID>4907</UserInternalID>
</User>
</Response>
</GetUserInternalIDByPersonalIDResult>
</GetUserInternalIDByPersonalIDResponse>
</soap:Body>
</soap:Envelope>
Any help would be greatly appreciated, this is driving me crazy!
----So if I don't get rid of the namespace attribute I get this error message:
Warning: simplexml_load_string() [function.simplexml-load-string]: Entity: line 1: parser warning : xmlns: URI LMSWebservice is not absolute in serviceTest2.php on line 16
Warning: simplexml_load_string() [function.simplexml-load-string]: LSchema"><soap:Body><GetUserInternalIDByPersonalIDResponse xmlns="LMSWebservice" in serviceTest2.php on line 16
Warning: simplexml_load_string() [function.simplexml-load-string]: ^ in serviceTest2.php on line 16
If I try using xPath to get at UserInternalID it returns an empty array. If what you're saying is correct and this is going into simpleXML correctly, then how do I access the UserInternalID node? Sorry, this is the first time using simpleXML and this is just perplexing me.
So just tried changing the NS
$feed = str_replace('xmlns="LMSWebservice"', 'xmlns="ns:LMSWebservice"', $xmlString);
which goes in without errors.
I tried this for the xPath
$ID = $sData->xpath('UserInternalID');
I understand this is probably completely wrong, but I haven't tried much else with this as it didn't seem to be going into simpleXML correctly in the first place. :/
So I've used
$ID = $sData->xpath('//UserInternalID');
echo $ID[0];
Which works perfectly. Thank you for all your help!
Through the extensive comments and your last edit finally the actual cause of your problem could be revealed, the xpath expression is wrong:
$ID = $sData->xpath('UserInternalID');
Wrong with it is the path, this matches no elements. Instead you could use:
$ID = (string) $xml->xpath('//UserInternalID')[0];
Or more verbose:
$ID = (string) $xml->xpath('//Response/User/UserInternalID')[0];
Key point here is that you write the correct path to the element you would like to query for.
Complete usage example:
<?php
/**
* SoapClient xml return string with simpleXML
*
* #link http://stackoverflow.com/q/19556414/367456
*/
$response = <<<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>
<GetUserInternalIDByPersonalIDResponse xmlns="LMSWebservice">
<GetUserInternalIDByPersonalIDResult>
<Response xmlns="">
<Timestamp date="24/10/2013" time="04:27:37" />
<User>
<UserInternalID>4907</UserInternalID>
</User>
</Response>
</GetUserInternalIDByPersonalIDResult>
</GetUserInternalIDByPersonalIDResponse>
</soap:Body>
</soap:Envelope>
RESPONSE;
$restore = libxml_use_internal_errors(TRUE);
$xml = simplexml_load_string($response);
libxml_use_internal_errors($restore);
echo $xml->xpath('//Response/User/UserInternalID')[0];
Output:
4907
Online Demo: https://eval.in/57149
$doc = new DOMDocument();
libxml_use_internal_errors(true);
$doc->loadHTML($response);
libxml_clear_errors();
$xml = $doc->saveXML($doc->documentElement);
$xml = simplexml_load_string($xml);
Use this helped me in a big way.
After spending SEVERAL frustrated hours on this I am asking for your help.
I am trying to get the content of particular nodes from a SOAP response.
The response is
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope"<xmlns:ns1="http://soap.xxxxxx.co.uk/">
<env:Body>
<ns1:PlaceOrderResponse>
<xxxxxOrderNumber></xxxxxOrderNumber>
<ErrorArray>
<Error>
<ErrorCode>24</ErrorCode>
<ErrorText>The+client+order+number+3002254+is+already+in+use</ErrorText>
</Error>
<Error>
<ErrorCode>1</ErrorCode>
<ErrorText>Aborting</ErrorText>
</Error>
</ErrorArray>
</ns1:PlaceOrderResponse>
</env:Body>
</env:Envelope>
I am trying to get at the nodes and children of <ErrorArray>.
Because of the XML containing namespaces
$XmlArray = new SimpleXMLElement($XmlStr);
foreach ($XmlArray->env:Envelope->env:Body->ns1:PlaceOrderResponse->ErrorArray->Error as $Error)
{
echo $Error->ErrorCode."<br />";
}
doesn't work.
I have read a number of articles such as
http://www.sitepoint.com/blogs/2005/10/20/simplexml-and-namespaces/
http://blog.stuartherbert.com/php/2007/01/07/using-simplexml-to-parse-rss-feeds/
and about 20 questions on this site, which unfortunately are not helping.
Even writing,
$XmlArray = new SimpleXMLElement($XmlStr);
echo "<br /><br /><pre>\n";
print_r($XmlArray);
echo "<pre><br /><br />\n";
gives
SimpleXMLElement Object
(
)
which makes me wonder if the soap response ($XmlStr) is actually a valid input for SimpleXMLElement.
It seems that the line
$XmlArray = new SimpleXMLElement($XmlStr);
is not doing what I expect it to.
Any help on how to get the nodes from the XML above would be very welcome.
Obviously getting it to work (having a working example) is what I need in the short term, but if someone could help me understand what I am doing wrong would be better in the long term.
Cheers.
Stu
You have to use SimpleXMLElement::children(), though at this point it would probably be easier to use XPath.
<?php
$XmlStr = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://soap.xxxxxx.co.uk/" >
<env:Body>
<ns1:PlaceOrderResponse>
<xxxxxOrderNumber></xxxxxOrderNumber>
<ErrorArray>
<Error>
<ErrorCode>24</ErrorCode>
<ErrorText>The+client+order+number+3002254+is+already+in+use</ErrorText>
</Error>
<Error>
<ErrorCode>1</ErrorCode>
<ErrorText>Aborting</ErrorText>
</Error>
</ErrorArray>
</ns1:PlaceOrderResponse>
</env:Body>
</env:Envelope>
XML;
$XmlArray = new SimpleXMLElement($XmlStr);
$t = $XmlArray->children("env", true)->Body->
children("ns1", true)->PlaceOrderResponse->
children()->ErrorArray->Error;
foreach ($t as $error) {
echo $error->ErrorCode, " " , $error->ErrorText, "<br />";
}
gives:
24 The+client+order+number+3002254+is+already+in+use
1 Aborting
A cheap and nasty way is to just simply remove the prefixes:
$xml = preg_replace('%<(\/)?(\S+):(\w+)%', '<$1$3', $xml);