XML Parsing error - php

I trying to parse XML file but getting parsing error.
Code ::
$xmlUrl = 'products.xml';
$xmlStr = file_get_contents($xmlUrl);
$xmlObj = simplexml_load_string($xmlStr);
XML file ::
<?xml version="1.0" encoding="UTF-8"?>
<result>
<orderlist>
<order_no>123123</order_no>
<date></date>
<client_name>Knapp's Donut Shop</client_name>
<sector>54</sector>
</orderlist>
</result>
I am getting error because of this tag
<client_name>Knapp's Donut Shop</client_name>

The conversion to a SimpleXML Object and the output works, see code example below.
Check your "products.xml" file for the correct UTF-8 encoding type.
<?php
$xml = <<< XML
<?xml version="1.0" encoding="UTF-8"?>
<result>
<orderlist>
<order_no>123123</order_no>
<date></date>
<client_name>Knapp & Donut Shop</client_name>
<sector>54</sector>
</orderlist>
</result>
XML;
$xml = str_replace(array("&", "&"), array("&", "&"), $xml);
$xmlObj = simplexml_load_string($xml);
var_dump($xmlObj);
echo PHP_EOL . $xmlObj->orderlist->client_name;
// Result: Knapp & Donut Shop

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);

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';

Strip SOAP Envelope for Saving Response to XML File

I have a SOAP response that I want to save to an XML file. When the response is written to the file, the SOAP envelope is written with it, making the XML file useless due to the error:
XML declaration allowed only at the start of the document in ...
In this case, XML is being declared twice:
<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body><ns1:NDFDgenResponse xmlns:ns1="http://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl">
<dwmlOut xsi:type="xsd:string">
<?xml version="1.0"?>
...
Is there a good way to strip out this SOAP envelope and just save what's between it?
Here's how I'm writing the response to the file:
$toWrite = htmlspecialchars_decode($client->__getLastResponse());
$fp = fopen('weather.xml', 'w');
fwrite($fp, $toWrite);
fclose($fp);
The problem is the htmlspecialchars_decode(). The envelope document contains other XML documents as text nodes. If you decode the entities in the XML document you will destroy it. Never use htmlspecialchars_decode() on an XML document.
Load the (envelope) XML into a DOM and read the needed value from it.
$xml = <<<'XML'
<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:NDFDgenResponse
xmlns:ns1="http://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl">
<dwmlOut xsi:type="xsd:string">
<?xml version="1.0"?>
<weather>XML</weather>
</dwmlOut>
</ns1:NDFDgenResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
XML;
$dom = new DOMDocument();
$dom->loadXml($xml);
$xpath = new DOMXPath($dom);
$xpath->registerNamespace('soap', 'http://schemas.xmlsoap.org/soap/envelope/');
$xpath->registerNamespace('ndfd', 'http://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl');
$innerXml = $xpath->evaluate(
'string(/soap:Envelope/soap:Body/ndfd:NDFDgenResponse/dwmlOut)'
);
echo $innerXml;
Output:
<?xml version="1.0"?>
<weather>XML</weather>

XML creation on the fly using PHP

I have a small requirement where I need to create a XML file on the fly. It was no problem for me to create a normal xml file which would be looking like this:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<item>
<name></name>
</item>
</root>
But my requirement is such that I need to create a XML file whose output is:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<item>
<name url = "C:\htdocs\proj1\source_file1"/>
<name url = "C:\htdocs\proj1\source_file2"/>
<name url = "C:\htdocs\proj1\source_file3"/>
</item>
</root>
I have tried in this fashion:
<?php
$domtree = new DOMDocument('1.0', 'UTF-8');
$domtree->formatOutput = true;
$xmlRoot = $domtree->createElement("root");
$xmlRoot = $domtree->appendChild($xmlRoot);
$item = $domtree->createElement("item");
$item = $xmlRoot->appendChild($item);
$name= $domtree->createElement("name");
$name = $item->appendChild($name);
$sav_xml = $domtree->saveXML();
$handle = fopen("new.xml", "w");
fwrite($handle, $sav_xml);
fclose($handle);
?>
But I wanted to append/add the url="path" to my elements. I have tried declaring variables with url and path but this throws me errors like:
Uncaught exception 'DOMException' with message 'Invalid Character Error'
Any ideas how to approach this problem!
Thanks
You just have to declare that attributes via php DOM:
...
$name= $domtree->createElement("name");
$urlAttribute = $domtree->createAttribute('url');
$urlAttribute->value = 'C:\htdocs\proj1\source_file1';
$name->appendChild($urlAttribute);
$item->appendChild($name);
...
Link to DOMDocument docs

SimpleXML PHP - Why DOM functions don't work, cdata trouble

Ive been trying every way possible to create cdata entries in my xml. My latest attempt is as follows. I can't even get passed for the first statement where im creating a new DOMDocument. Any ideas?
<?php
$xml = '
<?xml version="1.0" encoding="ISO-8859-1"?>
<cars>
<make name="Ford">
<model>Mustang</model>
</make>
<make name="Honda">
<model>Accord</model>
</make>
</cars>
';
$dom = new DOMDocument;
$dom->loadXML($xml);
$xml = simplexml_import_dom($dom);
print "working";
?>
You should not have any characters before the XML declaration. Remove the line break at $xml = '.
The neatest solution would be to use heredoc syntax:
$xml = <<<XML
<?xml version="1.0" encoding="ISO-8859-1"?>
<cars>
<make name="Ford">
<model>Mustang</model>
</make>
<make name="Honda">
<model>Accord</model>
</make>
</cars>
XML;
Have a look at: DOMDocument::createCDATASection
$xml = '<?xml version="1.0" encoding="ISO-8859-1"?>
<cars>
<make name="Ford">
<model>Mustang</model>
</make>
<make name="Honda">
<model>Accord</model>
</make>
</cars>
';
$dom = new DOMDocument;
$dom->loadXML($xml);
$cdataNode = $dom->createCDATASection('<&>');
$dom->documentElement->appendChild($cdataNode);
echo $dom->saveXml();
Output:
<?xml version="1.0" encoding="ISO-8859-1"?>
<cars>
<make name="Ford">
<model>Mustang</model>
</make>
<make name="Honda">
<model>Accord</model>
</make>
<![CDATA[<&>]]></cars>

Categories