replace "," with "." in xml file using php - php

I have a XML file that I want to import in my opencart store.
My XML file is:
<Model>100002</Model>
<Itemcode>10000200</Itemcode>
<Description>description of item</Description>
<Currency>EUR</Currency>
<IndustryCol1>5,98</IndustryCol1>
<IndustryCol2>2,88</IndustryCol2>
<IndustryCol3>2,8</IndustryCol3>
<IndustryCol4>2,7</IndustryCol4>
</PriceInfoRow>
</PriceInfo>
I need to replace comma with dot in
<IndustryCol1>5,98</IndustryCol1>
<IndustryCol2>2,88</IndustryCol2>
<IndustryCol3>2,8</IndustryCol3>
<IndustryCol4>2,7</IndustryCol4>
I need this because when I load the XML file with comma the script turns 5,98 to 5,00.
Any help?
Edit:
This is the function when i upload a xml file:
private function importXML($filename, $product_tag, $xml_options) {
$this->product_tag = $product_tag; $this->xml_data = ''; $fh =
fopen($filename, 'r'); $xml_parser =
xml_parser_create($this->file_encoding); xml_set_object($xml_parser,
$this); xml_set_element_handler($xml_parser, 'startTag', 'endTag');
xml_set_character_data_handler($xml_parser, 'cData');
xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, false);
while ($data = fread($fh, 4096)) { if (!xml_parse($xml_parser,
$data, feof($fh))) {
xml_parser_free($xml_parser);
return false; } if ($this->cron_fetch && $this->total_items_ready >= CRON_FETCH_NUM) {
xml_parser_free($xml_parser);
return true; } } xml_parser_free($xml_parser); return true; }

$xml = simplexml_load_string($s);
// Find all items which name starts with "IndustryCol"
$items = $xml->xpath('//*[starts-with(name(), "IndustryCol")]');
foreach($items as $k=>$v) {
// Replace node values
$items[$k][0] = str_replace(',', '.', $v);
}
echo $xml->asXML();
demo

Related

Iterate through a CSV file and get every value for a specified header?

I have a CSV file and I want to check if the row contains a special title. Only if my row contains a special title it should be converted to XML, other stuff added and so on.
My question now is, how can I iterate through the whole CSV file and get for every title the value in this field?
Because if it matches my special title I just want to convert the specified row where the title is matching my title. Maybe also an idea how I can do that?
Sample: CSV File
I must add that feature to my actual function. Because my actual function is just is converting the whole CSV to XML. But I just want to convert the specified rows.
My actual function:
function csvToXML($inputFilename, $outputFilename, $delimiter = ',')
{
// Open csv to read
$inputFile = fopen($inputFilename, 'rt');
// Get the headers of the file
$headers = fgetcsv($inputFile, 0, $delimiter);
// Create a new dom document with pretty formatting
$doc = new DOMDocument('1.0', 'utf-8');
$doc->preserveWhiteSpace = false;
$doc->formatOutput = true;
// Add a root node to the document
$root = $doc->createElement('products');
$root = $doc->appendChild($root);
// Loop through each row creating a <row> node with the correct data
while (($row = fgetcsv($inputFile, 0, $delimiter)) !== false) {
$container = $doc->createElement('product');
foreach ($headers as $i => $header) {
$child = $doc->createElement($header);
$child = $container->appendChild($child);
$value = $doc->createTextNode($row[$i]);
$value = $child->appendChild($value);
}
$root->appendChild($container);
}
$strxml = $doc->saveXML();
$handle = fopen($outputFilename, 'w');
fwrite($handle, $strxml);
fclose($handle);
}
Just check the title before adding the rows to XML. You could do it by adding the following lines:
while (($row = fgetcsv($inputFile, 0, $delimiter)) !== false) {
$specialTitles = Array('Title 1', 'Title 2', 'Title 3'); // titles you want to keep
if(in_array($row[1], $specialTitles)){
$container = $doc->createElement('product');
foreach ($headers as $i => $header) {
$child = $doc->createElement($header);
$child = $container->appendChild($child);
$value = $doc->createTextNode($row[$i]);
$value = $child->appendChild($value);
}
$root->appendChild($container);
}
}

How do i get the node-names from xml_parser()

I try to pre-sort and slice a big XML file for later processing via xml_parser
function CreateXMLParser($CHARSET, $bareXML = false) {
$CURRXML = xml_parser_create($CHARSET);
xml_parser_set_option( $CURRXML, XML_OPTION_CASE_FOLDING, false);
xml_parser_set_option( $CURRXML, XML_OPTION_TARGET_ENCODING, $CHARSET);
xml_set_element_handler($CURRXML, 'startElement', 'endElement');
xml_set_character_data_handler($CURRXML, 'dataHandler');
xml_set_default_handler($CURRXML, 'defaultHandler');
if ($bareXML) {
xml_parse($CURRXML, '<?xml version="1.0"?>', 0);
}
return $CURRXML;
}
function ChunkXMLBigFile($file, $tag = 'item', $howmany = 1000) {
global $CHUNKON, $CHUNKS, $ITEMLIMIT;
$CHUNKON = $tag;
$ITEMLIMIT = $howmany;
$xml = CreateXMLParser('UTF-8', false);
$fp = fopen($file, "r");
$CHUNKS = 0;
while(!feof($fp)) {
$chunk = fgets($fp, 10240);
xml_parse($xml, $chunk, feof($fp));
}
xml_parser_free($xml);
processChunk();
}
function processChunk() {
global $CHUNKS, $PAYLOAD, $ITEMCOUNT;
if ('' == $PAYLOAD) {
return;
}
$xp = fopen($file = "xmlTemp/slices/slice_".$CHUNKS.".xml", "w");
fwrite($xp, '<?xml version="1.0" ?>'."\n");
fwrite($xp, "<producten>");
fwrite($xp, $PAYLOAD);
fwrite($xp, "</producten>");
fclose($xp);
print "Written ".$file."<br>";
$CHUNKS++;
$PAYLOAD = '';
$ITEMCOUNT = 0;
}
function startElement($xml, $tag, $attrs = array()) {
global $PAYLOAD, $CHUNKS, $ITEMCOUNT, $CHUNKON;
if (!($CHUNKS||$ITEMCOUNT)) {
if ($CHUNKON == strtolower($tag)) {
$PAYLOAD = '';
}
} else {
$PAYLOAD .= "<".$tag;
}
foreach($attrs as $k => $v) {
$PAYLOAD .= " $k=".'"'.addslashes($v).'"';
}
$PAYLOAD .= '>';
}
function endElement($xml, $tag) {
global $CHUNKON, $ITEMCOUNT, $ITEMLIMIT;
dataHandler(null, "<$tag>");
if ($CHUNKON == strtolower($tag)) {
if (++$ITEMCOUNT >= $ITEMLIMIT) {
processChunk();
}
}
}
function dataHandler($xml, $data) {
global $PAYLOAD;
$PAYLOAD .= $data;
}
but how can I access the node-name??
.. I have to sort some items (with n nodes) out, before the slice-file is saved. the the XML is parsed line after line, right? so I have to save the nodes from a whole item temporarely and decide if the item is gonna be written to the file.. is there a way to do this?
Your code is effectively reading the entire source file every time you call the ChunkXMLBigFile function.
After your while loop you have all the elements, which you can then manipulate any way you like.
See the following questions about how to approach this:
How to sort a xml file using DOM
Sort XML nodes with PHP
If you parse the chunks after that in batches of $howmany you are where you want to be.
Tip: there are many examples online where this functionality is presented in an Object Orient Programming (OOP) approach where all the functions are inside a class. This would also eliminate the need of global variables which can cause some (read: a lot) of frustrations and confusion.

Converting XML to CSV using PHP

I need to convert an XML file to CSV.
I have a script but I am unsure of how to use it to my needs.
Here is the script
$filexml='141.xml';
if (file_exists($filexml)) {
$xml = simplexml_load_file($filexml);
$f = fopen('141.csv', 'w');
foreach ($xml->item as $item) {
fputcsv($f, get_object_vars($item),',','"');
}
fclose($f);
}
The file is called 141.xml and here is some of the code in the XML which I need to convert.
<?xml version="1.0" encoding="UTF-8" ?>
<rss xmlns:g="http://base.google.com/ns/1.0" version="2.0">
<channel>
<item>
<title><![CDATA[//title name]]></title>
<link><![CDATA[https://www.someurl.co.uk]]></link>
<description><![CDATA[<p><span>Demo Description</span></p>]]></description>
<g:id><![CDATA[4796]]></g:id>
<g:condition><![CDATA[new]]></g:condition>
<g:price><![CDATA[0.89 GBP]]></g:price>
<g:availability><![CDATA[in stock]]></g:availability>
<g:image_link><![CDATA[https://image-location.png]]></g:image_link>
<g:service><![CDATA[Free Shipping]]></g:service>
<g:price><![CDATA[0 GBP]]></g:price>
</item>
I am running the script from SSH using:
php /var/www/vhosts/mywebsite.co.uk/httpdocs/xml/convert.php
If you can help me, it would be really appreciated :)
Thanks
Consider passing XML data into an array $values and exporting array by row to csv.
Specifically, using the xpath() function for the XML extraction, iterate through each <item> and extract all its children's values (/*). By the way, I add headers in the CSV file.
$filexml='141.xml';
if (file_exists($filexml)) {
$xml = simplexml_load_file($filexml);
$i = 1; // Position counter
$values = []; // PHP array
// Writing column headers
$columns = array('title', 'link', 'description', 'id', 'condition',
'price', 'availability', 'image_link', 'service', 'price');
$fs = fopen('141.csv', 'w');
fputcsv($fs, $columns);
fclose($fs);
// Iterate through each <item> node
$node = $xml->xpath('//item');
foreach ($node as $n) {
// Iterate through each child of <item> node
$child = $xml->xpath('//item['.$i.']/*');
foreach ($child as $value) {
$values[] = $value;
}
// Write to CSV files (appending to column headers)
$fs = fopen('141.csv', 'a');
fputcsv($fs, $values);
fclose($fs);
$values = []; // Clean out array for next <item> (i.e., row)
$i++; // Move to next <item> (i.e., node position)
}
}
Try out below code. And the XML file is having syntax error, the closing tag for rss and channel is missing.
$filexml='141.xml';
if (file_exists($filexml))
{
$xml = simplexml_load_file($filexml);
$f = fopen('141.csv', 'w');
createCsv($xml, $f);
fclose($f);
}
function createCsv($xml,$f)
{
foreach ($xml->children() as $item)
{
$hasChild = (count($item->children()) > 0)?true:false;
if( ! $hasChild)
{
$put_arr = array($item->getName(),$item);
fputcsv($f, $put_arr ,',','"');
}
else
{
createCsv($item, $f);
}
}
}

PHP DOM remove child

I am trying to remove the parent node of <wcccanumber> from my xml, if it's content matches a certain criterion, but it keeps just removing the one node <wcccanumber>. How do I remove the whole parent node?
Heres my code:
$xml = new SimpleXMLElement('<xml/>');
if (file_exists("xml/units/E01.xml")) {
$xml = simplexml_load_file("xml/units/E01.xml");
echo "File exists";
echo "</br>";
$wcccanumber = "121202482";
foreach ($xml->call->wcccanumber as $call) {
if ($call == $wcccanumber) {
$dom = dom_import_simplexml($call);
$dom->parentNode->removeChild($dom);
$fp = fopen("xml/units/E01.xml","wb");
fwrite($fp,$xml->asXML());
fclose($fp);
}
}
}
Here is the xml:
<xml>
<call>
<wcccanumber>121202482</wcccanumber>
<currentcall>FALL</currentcall>
<county>W</county>
<id>82</id>
<location>234 E MAIN ST</location>
<callcreated>12:26:09</callcreated>
<station>HBM</station>
<units>E01</units>
<calltype>M</calltype>
<lat>45.5225067888299</lat>
<lng>-122.987112718574</lng>
<inputtime>12/18/2012 12:27:01 pm</inputtime>
</call>
</xml>
Iterate through call and compare $call->wcccanumber with $wcccanumber. Convert $call to dom and remove it (parentNode->removeChild).
foreach ($xml->call as $call) {
if ($call->wcccanumber == $wcccanumber) {
$dom = dom_import_simplexml($call);
$dom->parentNode->removeChild($dom);
$fp = fopen("xml/units/E01.xml","wb");
fwrite($fp,$xml->asXML());
fclose($fp);
}
}
If there are multiple deletions it makes sense to save only once after all deletions have been done.
$deletionCount = 0;
foreach ($xml->call as $call) {
if ($call->wcccanumber != $wcccanumber) {
continue;
}
$dom = dom_import_simplexml($call);
$dom->parentNode->removeChild($dom);
$deletionCount++;
}
if ($deletionCount) {
file_put_contents("xml/units/E01.xml", $xml->asXML());
}

Reset XML Parser PHP

Hi I'm using a class to parse my XML.
I have to parse request XML and response XML, and I'd like to do it with the same parser. When I parse the response XML, I keep getting junk after document element error.
I narrowed my XML down to <?xml version="1.0" encoding="UTF-8" ?><check></check> and I'm still getting the error, so the only thing I could think of is the second <?xml ..?> header being parsed as 'junk'.
What I basically want to do is reset the XML parser so it can start off as a new document, but I don't want to create a new parser object. Is this possible?
Edit:
I'm using the following code in my XmlParser object.
<?php
class XmlComponent extends Object {
private $parser, $c, $current_tag;
public $contents;
function initialize(&$controller, $settings = array())
{
$this->controller =& $controller;
$this->parser = xml_parser_create();
xml_set_object($this->parser, $this);
xml_set_element_handler($this->parser, "tag_open", "tag_close");
xml_set_character_data_handler($this->parser, "cdata");
xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
if (isset($settings['xml'])) {
$contents = $settings['xml'];
}
if (isset($settings['file'])) {
$f = fopen($settings['file'], 'r');
$contents = fread($f, filesize($settings['file']));
fclose($f);
}
debug($this->parse($contents));
}
public function parse($xml)
{
$xml = trim(preg_replace("/>\s+</", '><', $xml));
$this->contents = array();
$this->c = &$this->contents;
xml_parse($this->parser, $xml);
return xml_error_string(xml_get_error_code($this->parser))."\r\n".$xml;
}
//*/
public function xml($root)
{
$xml = '';
foreach ($root as $tag=>$elem) {
if (substr($tag, 0,1) != '#') {
foreach ($elem as $val) {
$xml .= '<'.$tag;
if (is_array($val) && isset($val['#attributes'])) {
foreach($val['#attributes'] as $a_key => $a_val) {
$xml .= ' '.$a_key.'="'.$a_val.'"';
}
}
$xml .= '>';
if (is_array($val) && isset($val['#data'])) {
$xml .= $val['#data'];
}
$xml .= $this->xml($val);
$xml .= '</'.$tag.'>';
}
}
}
return $xml;
}
//*/
private function tag_open($parser, $tag, $attributes)
{
if (!empty($attributes)) { $this->c[$tag][] = array('#attributes' => $attributes, '#parent' => &$this->c); }
else { $this->c[$tag][] = array('#parent' => &$this->c); }
$this->c =& $this->c[$tag][count($this->c[$tag]) - 1];
}
private function tag_close($parser, $tag)
{
$parent = &$this->c['#parent'];
unset($this->c['#parent']);
$this->c =& $parent;
}
private function cdata($parser, $data)
{
if (!empty($data)) {$this->c['#data'] = $data;}
}
//*/
}
?>
What I basically want to do is reset the XML parser so it can start off as a new document, but I don't want to create a new parser object. Is this possible?
No, you have to create a new parser. You can, of course, provide in your class a method that "resets" the parser; i.e., deletes the current one and creates a new one, hence hiding it from the class consumer.

Categories