simplexml_load_string cannot load XML / No error / result not === false - php

XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<result sync="false" version="2">
<action>start-subscription</action>
<action_result>
<code>103</code>
<detail>1 missing parameter</detail>
<missing_parameters>
<missing_parameter>
<key>operator</key>
</missing_parameter>
</missing_parameters>
<status>1</status>
</action_result>
<custom_parameters>
<custom_parameter>
<key>cp_REF</key>
<value>simpleLPADULTCHSMSV2___WoopGang------___Adjomo___external___paid___android___CH___WIFI___locale=fr_FR</value>
</custom_parameter>
</custom_parameters>
<customer>
<country>CH</country>
<language>en</language>
</customer>
<payment_parameters>
<channel>web</channel>
<method>OPERATOR</method>
<order>90330</order>
</payment_parameters>
<transactions>
<transaction>
<id>1308636894</id>
<status>-1</status>
</transaction>
</transactions>
<request_id>1591621_t593818e0f3913</request_id>
<reference>09045c8e-9ec1-4306-8699-5ac5306983b2</reference>
</result>
PHP:
$xml = file_get_contents("php://input");
$datas = array();
parse_str($xml, $datas);
$data = $datas['data'];
libxml_use_internal_errors(true);
$xml = simplexml_load_string($data);
if($xml === false){
foreach(libxml_get_errors() as $error) {
$this->_logCall(self::LOG_DIMOCO, $error->message,"--");
}
}else{
$this->_logCall(self::LOG_DIMOCO, 'loaded simpleXML '.print_r($xml), ' --');
}
Running that ends in the last ELSE and the result is "1"
Any idea what I'm doing wrong ?
I have to add some text because apparently its mostly code and not understandable. Now ? Now ? Now ? Now ?

print_r() (by default) doesn't return output, it prints it -- so you can't use it in a string context. If you want to do that, you can pass a truthy value as the second parameter to have it return the output instead of printing it:
$this->_logCall(self::LOG_DIMOCO, 'loaded simpleXML '.print_r($xml, true), ' --');

Related

PHP updating xml CDATA fields with DOMdocument

I have the following XML data:
<?xml version="1.0" encoding="utf-8"?>
<source>
<publisher>some-data</publisher>
<publisherurl>some-data</publisherurl>
<lastBuildDate>a-date</lastBuildDate>
<element>
<sub-element><![CDATA[some-data]]></sub-element>
</element>
</source>
I'm trying to use PHP's built in DOMdocument parser to update the text inside sub-element.
I've tried:
$dom=new DOMDocument();
$dom->load("document.xml");
$ele=$root->getElementsByTagName('element');
foreach ($ele as $e) {
$e->getElementsByTagName('sub-element')->item(0)->nodeValue = "new val";
}
this kind of works but it removes the CDATA and just replaces it with new-val. I want to preserve the CDATA field so I tried the following:
$dom=new DOMDocument();
$dom->load("document.xml");
$ele=$root->getElementsByTagName('element');
foreach ($ele as $e) {
$sub=$e->getElementsByTagName('sub-element');
foreach($sub->childNodes as $child) {
if ($child->nodeType == XML_CDATA_SECTION_NODE) {
$child->nodeValue = 'new-val';
}
}
}
This seems like it should work but PHP returns the following Notice
Undefined property: DOMNodeList::$childNodes
Feel like I'm on the right path but I just can't figure out what I'm doing wrong here. Does anyone know how to fix?
My end goal output is:
<?xml version="1.0" encoding="utf-8"?>
<source>
<publisher>some-data</publisher>
<publisherurl>some-data</publisherurl>
<lastBuildDate>a-date</lastBuildDate>
<element>
<sub-element><![CDATA[new-val]]></sub-element>
</element>
</source>
You need to compare against firstChild
$xml = '<?xml version="1.0" encoding="utf-8"?>
<source>
<publisher>some-data</publisher>
<publisherurl>some-data</publisherurl>
<lastBuildDate>a-date</lastBuildDate>
<element>
<sub-element><![CDATA[some-data]]></sub-element>
</element>
<element>
<sub-element>some-other-data</sub-element>
</element>
</source>';
$dom = new DOMDocument();
$dom->loadXML($xml);
$ele=$dom->getElementsByTagName('element');
foreach ($ele as $e) {
$item = $e->getElementsByTagName('sub-element')->item(0);
if($item->firstChild->nodeType == XML_CDATA_SECTION_NODE) { //<------
//it's CDATA do whatever
$item->firstChild->nodeValue = "new val";
} else {
//it's not , do something else
$item->nodeValue = "new val";
}
}
echo "<pre>";
print_r(htmlentities($dom->saveXML()));
echo "</pre>";
Output:
<?xml version="1.0" encoding="utf-8"?>
<source>
<publisher>some-data</publisher>
<publisherurl>some-data</publisherurl>
<lastBuildDate>a-date</lastBuildDate>
<element>
<sub-element><![CDATA[new val]]></sub-element>
</element>
<element>
<sub-element>new val</sub-element>
</element>
</source>
PS: if you don't have to make a distinction between CDATA or not, just use firstChild
foreach ($ele as $e) {
$item = $e->getElementsByTagName('sub-element')->item(0);
$item->firstChild->nodeValue = "new val";
}

conditional statement based formatting of XML responses from php curl

I am having difficulty formatting the XML response from a php curl XML API for INFOBIP. My code below loops SMS to mobile numbers. But I want to format the XML responses to show the messages successfully sent and those that were not successful using a conditional if else statement.
while ($row = mysql_fetch_array($result))
{
// XML-formatted data
$xmlString='
<SMS>
<authentication>
<username>'.$user.'</username>
<password>'.$pass.'</password>
</authentication>
<message>
<sender>'.$sender.'</sender>
<text>'.$message.'</text>
<recipients>
<gsm>'.$mobileno.'</gsm>
//<gsm>'.$mobileno1.'</gsm>
</recipients>
</message>
</SMS>';
$fields = "XML=" . urlencode($xmlString);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $postUrl);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
$response = curl_exec($ch);
curl_close($ch);
$xml = simplexml_load_string($response);
// Successfully sent messages usually outputs <status>0<status> while unsuccessful outputs 1,2,3
if($xml->status == '0') {
echo "message successfully delivered to ".$mobileno. "<br>" ;
}else{
echo "error sending message to ".$mobileno."<br>" ;
}
}
The problem I have is being able to set or parse the XML responses to get the <status> if successfully sent or not based on the XML status response. Currently this how the XML responses outputs the results without formatting.
<?xml version="1.0" encoding="UTF-8"?>
<results>
<result><status>1</status><messageid></messageid><destination>23421</destination></result> </results>
<?xml version="1.0" encoding="UTF-8"?> <results> <result><status>-13</status><messageid></messageid><destination>23412</destination></result> </results>
<?xml version="1.0" encoding="UTF-8"?> <results> <result><status>0</status><messageid></messageid><destination>23444</destination></result>
</results>
$str_soap_xml='
<?xml version="1.0" encoding="UTF-8"?>
<results>
<result>
<status>1</status>
<messageid></messageid>
<destination>23421</destination>
</result>
</results>
<?xml version="1.0" encoding="UTF-8"?>
<results>
<result>
<status>-13</status>
<messageid></messageid>
<destination>23412</destination>
</result>
</results>
<?xml version="1.0" encoding="UTF-8"?>
<results>
<result>
<status>0</status>
<messageid></messageid>
<destination>23444</destination>
</result>
</results>';
/*
manipulate the dodgy, invalid xml by firstly stripping out the XML Prologs
then give a new ROOT node ( as valid xml can only have one root node )
and then, to make sure, append a new XML Prolog
*/
$str_soap_xml='<?xml version="1.0" encoding="UTF-8"?><root>'.trim( str_replace( '<?xml version="1.0" encoding="UTF-8"?>', '', $str_soap_xml ) ).'</root>';
$total=0;
define('BR','<br />');
/* create the domdocument object & load the string */
$dom=new DOMDocument('1.0','utf-8');
$dom->loadXML( $str_soap_xml );
/* find all result nodes */
$col=$dom->getElementsByTagName('result');
/* iterate through each result and find it's children */
foreach( $col as $node ){
foreach( $node->childNodes as $child ){
echo $child->tagName.' '.$child->nodeValue.BR;
if( $child->tagName=='status' && $child->nodeValue==0 ) echo 'Bad foo!';
elseif( $child->tagName=='status' ) $total++;
}
}
$dom=$col=$node=$child=null;
echo 'total: '.$total.' add this to db';

Parsing an XML Caldav request in php

I'm trying to parse a request sent by ThunderBird to my CalDAV Server and from an example taken from stackoverflow with an XML like :
<?xml version="1.0" encoding="ISO-8859-1"?>
<products>
<last_updated>2009-11-30 13:52:40</last_updated>
<product>
<element_1>foo</element_1>
<element_2>foo</element_2>
<element_3>foo</element_3>
<element_4>foo</element_4>
</product>
</products>
Using the function :
$XMLr = new XMLReader;
$XMLr->open('test.xml');
$doc = new DOMDocument;
// move to the first <product /> node
while ($XMLr->read() && $XMLr->name !== 'product');
// now that we're at the right depth, hop to the next <product/> until the end of the tree
$node = simplexml_import_dom($doc->importNode($XMLr->expand(), true));
// now you can use $node without going insane about parsing
$children = $node->children();
foreach($children as $child)
{
echo $child->getName();
echo "\n";
}
I get the answer "element_1 element_2 element_3 element_4 ", but if I use the same function on my request :
<?xml version="1.0" encoding="UTF-8"?>
<D:propfind xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/" xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop>
<D:resourcetype/>
<D:owner/>
<D:current-user-principal/>
<D:supported-report-set/>
<C:supported-calendar-component-set/>
<CS:getctag/>
</D:prop>
</D:propfind>
Replacing $XMLr->name !== 'product' by $XMLr->name !== 'D:prop' I get a white screen...
What do I do wrong ?
How can I get the answer "ressourcetype owner current-user-principal etc ..." ?
I try with XMLReader and simplexml_import_dom without success but in opposite, with DomDocument you can do it:
// Just for display test results
$break_line = '<br>';
if (php_sapi_name() === 'cli') {
$break_line = "\n";
}
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<D:propfind xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/" xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop>
<D:resourcetype/>
<D:owner/>
<D:current-user-principal/>
<D:supported-report-set/>
<C:supported-calendar-component-set/>
<CS:getctag/>
</D:prop>
</D:propfind>';
$xml_document = new DomDocument(); // http://fr2.php.net/manual/fr/class.domdocument.php
$xml_document->loadXML($xml); // Or load file with $xml_document->load('test.xml);
$elements = $xml_document->getElementsByTagName('prop');
// $elements is a DOMNodeList object: http://fr2.php.net/manual/fr/class.domnodelist.php
foreach($elements as $element) {
// $element is a DOMElement object: http://fr2.php.net/manual/fr/class.domelement.php
$childs = $element->childNodes;
// $childs is DOMNodeList
foreach ($childs as $child) {
// $element is a DOMElement object
if ($child instanceof DOMElement) {
echo $child->nodeName . $break_line;
}
}
}
White screen normally means error.
Put error_reporting on E_ALL
error_reporting('E_ALL');

PHP - Parse, Read XML

Not too sure what I'm doing wrong with parsing/reading an xml document.
My guess is that it's not standardized, and I'm going to need a different process to read anything from the string.
If that's the case, then I'm rather excited to learn how someone would read the xml.
Here's what I've got, and what I'm doing.
example.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="someurl.php"?>
<response>
<status>Error</status>
<error>The error message I need to extract, if the status says Error</error>
</response>
read_xml.php
<?php
$content = 'example.xml';
$string = file_get_contents($content);
$xml = simplexml_load_string($string);
print_r($xml);
?>
I'm getting no result back from the print_r.
I switched the xml to something more standard, like:
<?xml version="1.0" encoding="ISO-8859-1"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
...and it worked fine. So I'm sure it's due to a non-standard format, passed back from the source I'm getting it from.
How would I extract the <status> and <error> tags?
Tek has a good answer, but if you want to use SimpleXML, you can try something like this:
<?php
$xml = simplexml_load_file('example.xml');
echo $xml->asXML(); // this will print the whole string
echo $xml->status; // print status
echo $xml->error; // print error
?>
EDIT: If you have multiple <status> and <error> tags in your XML, have a look at this:
$xml = simplexml_load_file('example.xml');
foreach($xml->status as $status){
echo $status;
}
foreach($xml->error as $error){
echo $error;
}
I'm assuming <response> is your root. If it isn't, try $xml->response->status and $xml->response->error.
I prefer to use PHP's DOMDocument class better.
Try something like this:
<?php
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="someurl.php"?>
<response>
<status>Error</status>
<error>The error message I need to extract, if the status says Error</error>
</response>';
$dom = new DOMDocument();
$dom->loadXML($xml);
$statuses = $dom->getElementsByTagName('status');
foreach ($statuses as $status) {
echo "The status tag says: " . $status->nodeValue, PHP_EOL;
}
?>
Demo: http://codepad.viper-7.com/mID6Hp

parsing xml with PHP simplexml_load_string

so i have this XML: the result of var_dump
string '
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<data>
<entry key="message Type">
<![
CDATA[
urgent
]
]></entry><entry key="message Title"><![
CDATA[
teswt
]
]></entry><entry key="message Body"><![
CDATA[
teasd
]
]></entry><entry key="message Priority"><![
CDATA[
1
]
]></entry></data>
' (length=260)
my code looks like this:
$xml = simplexml_load_string($tablerow['data']);
$inputs = $xml->xpath("/schema/user_input[#type!='hidden']/input|/schema/input");
foreach($inputs as $cur_input) {
$cur_input_name = (string)$cur_input['name'];
$cur_input_value = $task_input_values[$cur_input_name];
$input_name = isset($cur_input['label']) ? (string)$cur_input['label'] : $cur_input['name'];
}
var_dump($tablerow['data']);
$tablerow['data'] is the XML from the DB. any help how to get the message Title value from this??
Thanks!
The XPath expression you are using doesn't even resemble the XML document you posted, so I don't know how you would expect to ever find the values you are looking for. The following will extract "teswt" from your sample XML document:
<?php
$xml = simplexml_load_string($tablerow['data']);
$title = '';
foreach ($xml->entry as $entry) {
if ((string) $entry['key'] == 'message Title') {
$title = (string) $entry;
break;
}
}
echo $title;
?>
Edit: Updated to use the SimpleXML "style" rather than XPath.
Your XML should be in proper way.
Check This
<?php
$xmlString = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<data>
<entry key="message Type">
<![CDATA[urgent]]>
</entry>
<entry key="message Title">
<![CDATA[teswt]]>
</entry>
<entry key="message Body">
<![CDATA[xxxxx]]>
</entry>
<entry key="message Priority">
<![CDATA[1]]>
</entry>
</data>';
$xml = simplexml_load_string($xmlString);
foreach ($xml->entry as $entry)
{
echo $entry['key']."<br/>";
}
?>

Categories