PHP - Convert XML to CSV using fputcsv - php

How do I convert the following XML to CSV using fputcsv
<?xml version="1.0" encoding="utf-8"?>
<PRODUCTINFORMATION>
<SUPPLIER>Company</SUPPLIER>
<PRODUCTS>
<PRODUCT>
<PRODUCT_NUMBER>AR1249-16</PRODUCT_NUMBER>
<PRODUCT_BASE_NUMBER>AR1249</PRODUCT_BASE_NUMBER>
<PRODUCT_ID>10134325</PRODUCT_ID>
</PRODUCT>
<PRODUCT>
<PRODUCT_NUMBER>AR1253-16</PRODUCT_NUMBER>
<PRODUCT_BASE_NUMBER>AR1253</PRODUCT_BASE_NUMBER>
<PRODUCT_ID>10134300</PRODUCT_ID>
</PRODUCT>
<PRODUCT>
<PRODUCT_NUMBER>AR1424-03</PRODUCT_NUMBER>
<PRODUCT_BASE_NUMBER>AR1424</PRODUCT_BASE_NUMBER>
<PRODUCT_ID>10147594</PRODUCT_ID>
</PRODUCT>
</PRODUCTS>
</PRODUCTINFORMATION>
My PHP is:
<?php
$xml = simplexml_load_file('prodinfo.xml');
$csv = fopen('prodinfo.csv', 'w');
foreach($xml->PRODUCTS->PRODUCT as $element) {
foreach($element->PRODUCT_NUMBER as $productNumber){
foreach($element->PRODUCT_BASE_NUMBER as $productBaseNumber){
echo $productNumber ,";", $productBaseNumber. '<BR>' ;
//fputcsv($csv, get_object_vars($productNumber),',','"');
//fclose($csv);
}
}
}
?>

You don't need so many foreach() loops to get each product. It's also easier to build the array from each item as it's fixed and only a few fields...
$csv = fopen('prodinfo.csv', 'w');
fputcsv($csv, ["PRODUCT_NUMBER","PRODUCT_BASE_NUMBER","PRODUCT_ID"]
,',','"');
foreach($xml->PRODUCTS->PRODUCT as $element) {
fputcsv($csv, [(string)$element->PRODUCT_NUMBER,
(string)$element->PRODUCT_BASE_NUMBER,
(string)$element->PRODUCT_ID
],',','"');
}
fclose($csv);

Related

SimpleXML foreach doesn't work

I have following XML (source.xml):
<SHOP>
<SHOPITEM>
<ITEM_ID>3664</ITEM_ID>
<PRODUCT>Product n.1</PRODUCT>
<PRODUCT_NAME>Product n.1</PRODUCT_NAME>
<VARIANT_NAME/>
<MANUFACTURER>Jeffrey</MANUFACTURER>
<CODE>ABC123</CODE>
<EAN>123456789</EAN>
<DESCRIPTION>
Maybe later...
</DESCRIPTION>
<DESCRIPTION_HTML/>
<CATEGORIES>
<CATEGORY id="1" parent_id="0">ABx</CATEGORY>
</CATEGORIES>
</SHOPITEM>
<SHOPITEM>
...etc
And following code:
$xml = simplexml_load_file("source.xml", NULL, LIBXML_NOCDATA);
foreach ($xml->shopitem as $shopitem) {
echo $shopitem->item_id;
}
Unfortunately, it doesn't work. Even if I put echo 'a'; into foreach cycle, nothing appears. XML is valid. Tried var_dump($xml) and the XML looks to be loaded correctly. What is wrong? Thank you.
$xml = simplexml_load_file("source.xml", NULL, LIBXML_NOCDATA);
foreach ($xml->SHOPITEM as $shopitem) {
echo $shopitem->ITEM_ID;
}

SimpleXMLElement output format

I'm using SimpleXMLElement for create datafeed page: Here the code:
$xml = new SimpleXMLElement("<Products />");
foreach ($products as $pro) {
$track = $xml -> addChild('Product');
$track -> addChild('simple_sku', "<![CDATA[ ABC ]]>");
}
Header('Content-type: text/xml');
print($xml -> asXML());
and the output:
<Products>
<Product>
<simple_sku><![CDATA[ ABC ]]></simple_sku>
</Product>
</Products>
I want to know how to turn output into format like this:
<Products>
<Product>
<simple_sku>
<![CDATA[ ABC ]]>
</simple_sku>
</Product>
<Products>
Thanks you a lot.
It's not possible with SimpleXML so I advice you to use DOMDocument.
Usage example:
$dom = new DOMDocument('1.0');
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML($simpleXml->asXML());

Explode the attribute in XML File

I have an XML with attribute like this:
<products>
<product ProductName="One" ProductCategory="Software::Utilities::Email">
<product ProductName="Two" ProductCategory="Software::Video::Editing">
<product ProductName="Three" ProductCategory="Software::Audio::Converter">
</products>
And how can I explode the "ProductCategory" attribute and separated it like this:
<products>
<product ProductName="One" ProductCategory="Software">
<product ProductName="One" ProductCategory="Utilities">
<product ProductName="One" ProductCategory="Email">
<product ProductName="Two" ProductCategory="Software">
<product ProductName="Two" ProductCategory="Video">
<product ProductName="Two" ProductCategory="Editing">
<product ProductName="Three" ProductCategory="Software">
<product ProductName="Three" ProductCategory="Audio">
<product ProductName="Three" ProductCategory="Converter">
</products>
An Example for you
<?php
$string = <<<XML
<products>
<product ProductName="One" ProductCategory="Software::Utilities::Email"></product>
<product ProductName="Two" ProductCategory="Software::Video::Editing"></product>
<product ProductName="Three" ProductCategory="Software::Audio::Converter"></product>
</products>
XML;
$xml = simplexml_load_string($string);
$obj = json_decode(json_encode($xml), true);
$new_xml = '<products>';
foreach($obj['product'] as $val){
$name = $val['#attributes']['ProductName'];
$pro = explode('::', $val['#attributes']['ProductCategory']);
foreach($pro as $k=>$v){
$new_xml .= '<product ProductName="'.$name.'" ProductCategory="'.$v.'"></product>';
}
}
$new_xml .= '</products>';
$file = fopen("test.xml","w");
fwrite($file, $new_xml);
fclose($file);
?>
You example XML is not valid XML. Make sure to close the product element nodes.
Load the source document into a DOM, create a new target DOM. Import the document element into the target (without child). This will create a copy of that node.
Iterate the product nodes and read the ProductCategory attribute, explode it into an array. Iterate the array an copy the node into the target document (for each value), change the attribute to the value.
$source = new DOMDocument();
$source->loadXml($xml);
$xpath = new DOMXPath($source);
$target = new DOMDocument();
$target->formatOutput = true;
$root = $target->appendChild($target->importNode($source->documentElement));
foreach ($xpath->evaluate('/products/product') as $node) {
$list = explode('::', $node->getAttribute('ProductCategory'));
foreach ($list as $value) {
$newNode = $root->appendChild($target->importNode($node));
$newNode->setAttribute('ProductCategory', $value);
}
}
echo $target->saveXml();
Demo: https://eval.in/209729

How insert PHP array in XML?

Hello to all i have a little problem, i have one array like this
$slike=array('1.jpg','2.jpg')
And another XML that looks like this
<?xml version='1.0' encoding='UTF-8'?>
<settings>
<show_context_menu>yes</show_context_menu>
<hide_buttons_delay>2</hide_buttons_delay>
<thumbs_width>200</thumbs_width>
<horizontal_space_btween_buttons>0</horizontal_space_btween_buttons>
<buttons_margins>0</buttons_margins>
</settings>
How to insert $slike in that XML, that new XML looks like this:
<?xml version='1.0' encoding='UTF-8'?>
<settings>
<show_context_menu>yes</show_context_menu>
<hide_buttons_delay>2</hide_buttons_delay>
<thumbs_width>200</thumbs_width>
<horizontal_space_btween_buttons>0</horizontal_space_btween_buttons>
<buttons_margins>0</buttons_margins>
<image>1.jpg</image>
<image>2.jpg</image>
</settings>
Txanks in advance
No idea into which problem you did run, but it's rather trivial using an XML library, e.g. even with SimpleXML in your case:
$slike = array('1.jpg','2.jpg');
$name = 'image';
$doc = new SimpleXMLElement($xml);
foreach($slike as $file) {
$doc->addChild($name, $file);
}
echo $doc->asXML();
The $xml in this example is the xml string from your question. Output:
<?xml version="1.0" encoding="UTF-8"?>
<settings>
<show_context_menu>yes</show_context_menu>
<hide_buttons_delay>2</hide_buttons_delay>
<thumbs_width>200</thumbs_width>
<horizontal_space_btween_buttons>0</horizontal_space_btween_buttons>
<buttons_margins>0</buttons_margins>
<image>1.jpg</image><image>2.jpg</image></settings>
What about something like this:
header("Content-Type: text/xml; charset=utf-8"); // added this line - that way the browser will render it as XML
$slike = array('1.jpg','2.jpg');
$xml = "<?xml version='1.0' encoding='UTF-8'?>
<settings>
<show_context_menu>yes</show_context_menu>
<hide_buttons_delay>2</hide_buttons_delay>
<thumbs_width>200</thumbs_width>
<horizontal_space_btween_buttons>0</horizontal_space_btween_buttons>
<buttons_margins>0</buttons_margins>";
foreach($slike as $s){
$xml.= "<image>".$s."</image>"; // create a new <image> node for each image in array
}
$xml .= "</settings>";
print_r($xml);
Outputs this:
<?xml version='1.0' encoding='UTF-8'?>
<settings>
<show_context_menu>yes</show_context_menu>
<hide_buttons_delay>2</hide_buttons_delay>
<thumbs_width>200</thumbs_width>
<horizontal_space_btween_buttons>0</horizontal_space_btween_buttons>
<buttons_margins>0</buttons_margins>
<image>1.jpg</image>
<image>2.jpg</image>
</settings>
http://php.net/manual/en/book.simplexml.php
The syntax looks something like this for your example
<aaaa Version="1.0">
<bbb>
<cccc>
<dddd Id="id:pass" />
<eeee name="hearaman" age="24" />
</cccc>
</bbb>
</aaaa>
$xml = new SimpleXMLElement($xmlString);
echo $xml->bbb->cccc->dddd['Id'];
echo $xml->bbb->cccc->eeee['name'];
// or...........
foreach ($xml->bbb->cccc as $element) {
foreach($element as $key => $val) {
echo "{$key}: {$val}";
}
}

update/append data to xml file using php

this may sound pretty straight forward, but still I want to post this question in the forum. I have a xml file, which needs to be appended with data after the main element and save the xml file without overwriting the existing xml file but to append the data to already existing data and update the xml file.
For example my xml data looks something similar to this:
<maincontent>
<headercontent>
<product num="2102">
<name>MSG</name>
<category>Wellness</category>
<available content="YES"></available>
</product>
<product num="2101">
<name>YSD</name>
<category>Music</category>
<available content="NO"></available>
</product>
<product num="2100">
<name>RCS</name>
<category>Media</category>
<available content="YES"></available>
</product>
</headercontent>
</maincontent>
I want to add another product with all the info and append the newly added data at the top so that the newly added data should come after the headercontent.
Data to be added:
<product num="2103">
<name>AGB</name>
<category>Movies</category>
<available content="YES"></available>
</product>
The updated xml file should be looking like this as shown below:
<maincontent>
<headercontent>
<product num="2103">
<name>AGB</name>
<category>Movies</category>
<available content="YES"></available>
</product>
<product num="2102">
<name>MSG</name>
<category>Wellness</category>
<available content="YES"></available>
</product>
<product num="2101">
<name>YSD</name>
<category>Music</category>
<available content="NO"></available>
</product>
<product num="2100">
<name>RCS</name>
<category>Media</category>
<available content="YES"></available>
</product>
</headercontent>
</maincontent>
Any useful advice or a piece of example code would be really helpful.
Edit:
sorry guys I haven't posted any php code, my fault. Here is the code which I have been working on:
Thanks
<?php
$xmldoc = new DomDocument();
$xmldoc->formatOutput = true;
$productNum = "2103";
$name = "AGB";
$category = "Movies";
$content = "YES";
if($xml = file_get_contents('main.xml')){
$xmldoc->loadXML($xml);
$root = $xmldoc->firstChild;
$newElement = $xmldoc->createElement('product');
$root->appendChild($newElement);
$numAttribute = $xmldoc->createAttribute("num");
$numAttribute->value = $productNum;
$newElement->appendChild($numAttribute);
$nameElement = $xmldoc->createElement('name');
$root->appendChild($nameElement);
$nameText = $xmldoc->createTextNode($name);
$nameElement->appendChild($nameText);
$categoryElement = $xmldoc->createElement('category');
$root->appendChild($categoryElement);
$categoryText = $xmldoc->createTextNode($category);
$categoryElement->appendChild($categoryText);
$availableElement = $xmldoc->createElement('available');
$root->appendChild($availableElement);
$availableAttribute = $xmldoc->createAttribute("content");
$availableAttribute->value = $content;
$availableElement->appendChild($availableAttribute);
$xmldoc->save('main.xml');
}
?>
My xml file gets updated but the data is added to the firstchild and that too at the bottom, instead I want to add data after and in the beginning as shown above.
Here is my output:
<maincontent>
<headercontent>
<product num="2102">
<name>MSG</name>
<category>Wellness</category>
<available content="YES"/>
</product>
<product num="2101">
<name>YSD</name>
<category>Music</category>
<available content="NO"/>
</product>
<product num="2100">
<name>RCS</name>
<category>Media</category>
<available content="YES"/>
</product>
</headercontent>
<product num="2103"/><name>AGB</name><category>Movies</category><available content="YES"/></maincontent>
Any advice?
This will work.
<?php
$xmldoc = new DomDocument( '1.0' );
$xmldoc->preserveWhiteSpace = false;
$xmldoc->formatOutput = true;
$productNum = "2103";
$name = "AGB";
$category = "Movies";
$content = "YES";
if( $xml = file_get_contents( 'main.xml') ) {
$xmldoc->loadXML( $xml, LIBXML_NOBLANKS );
// find the headercontent tag
$root = $xmldoc->getElementsByTagName('headercontent')->item(0);
// create the <product> tag
$product = $xmldoc->createElement('product');
$numAttribute = $xmldoc->createAttribute("num");
$numAttribute->value = $productNum;
$product->appendChild($numAttribute);
// add the product tag before the first element in the <headercontent> tag
$root->insertBefore( $product, $root->firstChild );
// create other elements and add it to the <product> tag.
$nameElement = $xmldoc->createElement('name');
$product->appendChild($nameElement);
$nameText = $xmldoc->createTextNode($name);
$nameElement->appendChild($nameText);
$categoryElement = $xmldoc->createElement('category');
$product->appendChild($categoryElement);
$categoryText = $xmldoc->createTextNode($category);
$categoryElement->appendChild($categoryText);
$availableElement = $xmldoc->createElement('available');
$product->appendChild($availableElement);
$availableAttribute = $xmldoc->createAttribute("content");
$availableAttribute->value = $content;
$availableElement->appendChild($availableAttribute);
$xmldoc->save('main.xml');
}
?>
Hope this helps.

Categories