Differences between two xml strings using php - php

I'm trying to compare and check the differences between two xml strings but my code is not detecting any changes in xml strings!
for ex my first string contains :
<Result>
<pid>10</pid>
<DocID>29</DocID>
<Response>True</Response>
<DocID>60<DocID>
<Blvd_Name>dfdfdfdfd</Blvd_Name>
<Alley_Name>dfd</Alley_Name>
<Plate_Number>654654</Plate_Number>
<Post_Code>654654654</Post_Code>
<Phone_1>654654</Phone_1>
<Phone_2>654654564</Phone_2>
<Fax>2323232</Fax>
<Website>ewewew</Website>
<Mobile_No>23232323232</Mobile_No>
<Information>
<Info>
<National_Code>106397854</National_Code>
<Start_Activity_Date>2015-12-22 00:00:00</Start_Activity_Date>
<End_Activity_Date>2016-01-03 00:00:00</End_Activity_Date>
</Info>
</Information>
<Service_Times>
<Service_Time>15:30 - 17:45</Service_Time>
</Service_Times>
</Result>
the second string is :
<Result>
<pid>10</pid>
<DocID>29</DocID>
<Response>True</Response>
<DocID>60<DocID>
<Blvd_Name>dfdfdfdfd</Blvd_Name>
<Alley_Name>dfd</Alley_Name>
<Plate_Number>654654</Plate_Number>
<Post_Code>654654654</Post_Code>
<Phone_1>11111</Phone_1>
<Phone_2>6546111154564</Phone_2>
<Fax>11111</Fax>
<Website>11111</Website>
<Mobile_No>11111</Mobile_No>
<Information>
<Info>
<National_Code>106397854</National_Code>
<Start_Activity_Date>2015-12-22 8:01:50</Start_Activity_Date>
<End_Activity_Date>2016-01-03 11:20:10</End_Activity_Date>
</Info>
</Information>
<Service_Times>
<Service_Time>15:30 - 17:45</Service_Time>
</Service_Times>
</Result>
as you can see there are some differences in the values of the objects!
I've tried simplexmlload and then array_diff and jason encode and decode and comparing the jason but there was not chance to detect the differences.
any suggestion how to accomplish that ?
my array diff code :
$result = array_diff($Data1, $Data2);
if(empty($result)){
// the XML documents are the same
$res = "No changes";
} else {
// they are different
$res = "There are Some changes";
}

You can leave the data as raw text ane see the difference by using the following
<?php
$difference = xdiff_string_diff($Data1, $Data2);

Ok I solved the problem using simple if comparison method and it worked.
I first opened two xml files and then i copared them using method below, if i change a value/structure in second xml file it gives me "there are some changes".
$file = './Result.xml';
if (file_exists($file)) {
$Data = file_get_contents($file);
} else {
exit('Failed to open ' . $file);
}
$file2 = './Result2.xml';
if (file_exists($file2)) {
$Data2 = file_get_contents($file2);
} else {
exit('Failed to open ' . $file2);
}
if ($Data === $Data2) {
// the XML documents are the same
$res = "No changes";
} else {
// they are different: print the reason why
$res = "There are Some changes";
}

Related

PHP gzread, gzfile, gzopen, etc.. all strip tags off of XML and return only the values [duplicate]

This question already has answers here:
How to echo XML file in PHP
(10 answers)
Output raw XML using php
(5 answers)
Closed 1 year ago.
I have .gz files that contain xml files. I've tried every combination of all the different things shown in the code below. Any time one of the gz..... methods "works" it returns the values contained inside the XML files will all the tags and metadata gone. For example, if the xml file looks like this:
<?xml version="1.0" encoding="UTF-8" ?>
<tag1>
<taga>
This
</taga>
<tagb>
is the stuff
</tagb>
</tag1>
<tag2>
<taga>
I get but only
</taga>
<tagb>
This
</tagb>
</tag2>
What I get is:
This is the stuff I get but only This
Here's the code:
<?php
$mailfileObj->zipfile = 'path/to/gzfile.gz'; //ignore the fact that it says zipfile, it is a .gz file
try{
$opengzfile = gzopen($mailfileObj->zipfile, "r");
$contents = gzread($opengzfile, filesize($mailfileObj->zipfile));
gzclose($opengzfile);
var_dump($contents);
echo '<br>';
//$opengzfile = fopen($mailfileObj->zipfile, "r");
//$contents = fread($opengzfile, filesize($mailfileObj->zipfile));
//fclose($opengzfile);
//$contents = file_get_contents($mailfileObj->zipfile);
$contents2 = '';
$lines = gzfile($mailfileObj->zipfile);
foreach ($lines as $line) {
echo $line;
$contents2 = $contents2.$line;
}
//var_dump($contents);
//echo '<br>';
//var_dump($contents);
//echo $contents . '<br><br>';
//$xmlfilegz = $mailfileObj->filename.'.xml';
//$openxmlfile = fopen($xmlfilegz, "w");
//fwrite($openxmlfile, $contents);
//fclose($openxmlfile);
$opengzfile = fopen($mailfileObj->zipfile, "r");
$contents2 = fread($opengzfile, filesize($mailfileObj->zipfile));
fclose($opengzfile);
//$contents2 = file_get_contents($mailfileObj->zipfile);
//$contents2 = gzdecode($contents);
$contents2 = gzinflate($contents);
//$contents2 = gzuncompress($contents);
var_dump($contents2);
}
catch(Exception $e){
echo 'Caught exception: ' . $e->getMessage() . '<br>';
}
?>
What is wrong here? What am I missing?
Thank you.
You're putting the XML in an HTML web page, so the browser is interpreting the XML tags as HTML tags.
Use htmlentities() to encode them so they'll be rendered literally.
foreach ($lines as $line) {
echo htmlentities($line);
$contents2 = $contents2.$line;
}
You might want to show this in a <pre> block so the newlines and indentation will be preserved.

PHP mysql - Generating a sitemaps without exceeding 50k rows limit

I have the follwing PHP / MYSQL sitemap that generates a sitemap into the browser. How can i make it save itself to a file and split on 50.000 ? i cant get it to work properly as the script just outputs into plain text. I want the script to output into a file
currently
<?
$xmlfile = 'sitemap.xml';
// this variable will contain the XML sitemap that will be saved in $xmlfile
$xmlsitemap = '<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
// Connection data (server_address, name, password, database_name)
$hostdb = '';
$userdb = '';
$passdb = '';
$namedb = '';
try {
// Connect and create the PDO object
$conn = new PDO("mysql:host=$hostdb; dbname=$namedb", $userdb, $passdb);
$conn->exec("SET CHARACTER SET utf8"); // Sets encoding UTF-8
// Define and perform the SQL SELECT query
$sql = "SELECT `shortUrl` FROM `shorturl`";
$result = $conn->query($sql);
// If the SQL query is succesfully performed ($result not false)
if($result !== false) {
// Parse the result set, and add the URL in the XML structure
foreach($result as $row) {
$xmlsitemap .= '
<url>
<loc>'. $row['shortUrl'] .'</loc>
<priority>0.5</priority>
<changefreq>weekly</changefreq>
</url>';
}
}
$conn = null; // Disconnect
}
catch(PDOException $e) {
echo $e->getMessage();
}
$xmlsitemap .= '</urlset>';
file_put_contents($xmlfile, $xmlsitemap); // saves the sitemap on server
// outputs the sitemap (delete this instruction if you not want to display the sitemap in browser)
echo $xmlsitemap;
?>
Let's take a look at the code that generating url records..
<url>
<loc>'. $row['shortUrl'] .'</loc>
<priority>0.5</priority>
<changefreq>weekly</changefreq>
</url>';
As above, one record contains 5 rows. So your array must contains max 10.000 records right ?
If we split our array into the chunks which contains max 10.000 records, we can easily save each chunk records in different files.
try {
// connect db and get records
# give attention here
$chunks = array_chunk($result, 10000)
// If the SQL query is succesfully performed ($result not false)
if($result !== false) {
// Parse the result set, and add the URL in the XML structure
foreach ($chunks as $key => $chunk) {
$xmlsitemap .= '</urlset $namespaces>';
foreach ($chunk as $row){
$xmlsitemap .= '
<url>
<loc>' . $row['shortUrl'] . '</loc>
<priority>0.5</priority>
<changefreq>weekly</changefreq>
</url>';
}
$xmlsitemap .= '</urlset>';
file_put_contents("path/to/directory/sitemap-".$key.".xml", $xmlsitemap);
}
}
}
// check errors
Btw don't forget to create sitemap index for those
Welcome to StackOverflow.
Simply run a counter in your foreach and break it to your desired value.
Not tested code is below
if($result !== false) {
// Parse the result set, and add the URL in the XML structure
$counter = 0;
foreach($result as $row) {
$counter++
$xmlsitemap .= '
<url>
<loc>'. $row['shortUrl'] .'</loc>
<priority>0.5</priority>
<changefreq>weekly</changefreq>
</url>';
if($counter==4900){
break;
}
}
}

PHP CSV to XML how to deal with pipe delimited strings

Firstly I know this a rather long/detailed post if you are looking for the gist of my problem you can jump to the bottom where I have a TLDR. Thanks in advance to all commenters
I have been working on a feature for my clients website. They have an older version of Microsoft Excel on MAC which does not support .XML - the store system they have uses .XML
So I need to code the ability to convert CSV into XML, but the XML must conform to the structure required by the store component. I have already coded an XML to CSV function which does work.
This is the XML output by the store system (I have removed the values for security of my client's customers):
<orders>
<order>
<order_id>38</order_id>
<order_number>000015</order_number>
<order_status>Authorized</order_status>
<order_date>0000-00-00 00:00:00</order_date>
<customer_email>test#someemail.ca</customer_email>
<order_amount>order total</order_amount>
<base_order_amount>pre shipping order total</base_order_amount>
<shipping_type>Basic Shipping</shipping_type>
<shipping_price> $0.00</shipping_price>
<billing_first_name>Name</billing_first_name>
<billing_last_name>B</billing_last_name>
<billing_address1>PO / Add</billing_address1>
<billing_address2></billing_address2>
<billing_city>Town</billing_city>
<billing_state_province>province</billing_state_province>
<billing_country>Canada</billing_country>
<billing_postal_code>postal code</billing_postal_code>
<billing_phone></billing_phone>
<emt_quest>test</emt_quest>
<emt_answ>test</emt_answ>
<emt_answ_conf>test</emt_answ_conf>
<shipping_first_name>Name</shipping_first_name>
<shipping_last_name>B</shipping_last_name>
<shipping_address1>PO / Add</shipping_address1>
<shipping_address2></shipping_address2>
<shipping_city>Town</shipping_city>
<shipping_state_province>province</shipping_state_province>
<shipping_country>Canada</shipping_country>
<shipping_postal_code>postal code</shipping_postal_code>
<shipping_phone></shipping_phone>
<items>
<item>
<item_name>Sample Item</item_name>
<item_price>$8.00</item_price>
<item_quantity>12</item_quantity>
</item>
<item>
<item_name>Sample Item 2</item_name>
<item_price>$12.00</item_price>
<item_quantity>12</item_quantity>
</item>
</items>
</order>
This is the code of my XML to CSV function
<?php
function xml2csv($xmlFile, $xPath) {
$csvData = "";
// Load the XML file
$xml = simplexml_load_file($xmlFile);
// xpath to search
$path = $xml->order;
//get headers (xpath must match above)
$headers = get_object_vars($xml->order[0]);
// Loop through the first row to get headers
foreach($headers as $key => $value){
$csvData .= $key . ',';
}
// Trim off the extra comma
$csvData = trim($csvData, ',');
// Add an LF
$csvData .= "\n";
foreach($path as $item) {
// Loop through the elements in specificed xpath
foreach($item as $key => $value) {
//check for a second generation children of specified first generation child
if ($key == "items") {
$itemString = "";
// if first generation child has children then loop through each second gen child
foreach ($item->children() as $child) {
// loop through each xpath of second generation child
foreach($child as $value) {
// for value of each xpath of second generation child get value as out
foreach($value->children() as $out) {
//combine each value into itemString for export to .csv
$itemString .= $out . "|";
}
}
}
// place item string in csvData string and remove extra pipe
$csvData .= trim($itemString, "|");
}
//else put xpath values of first geneartion child in .csv
else {
$csvData .= trim($value) . ',';
}
}
// Trim off the extra comma
$csvData = trim($csvData, ',');
// Add an LF
$csvData .= "\n";
}
// Return the CSV data
return $csvData;
}
When called with a given .XML file from the store system it outputs the following .CSV file (I have used dummy values the 'item price' is not accidental)
order_id,order_number,order_status,order_date,customer_email,order_amount,base_order_amount,shipping_type,shipping_price,billing_first_name,billing_last_name,billing_address1,billing_address2,billing_city,billing_state_province,billing_country,billing_postal_code,billing_phone,emt_quest,emt_answ,emt_answ_conf,medicinal_use,shipping_first_name,shipping_last_name,shipping_address1,shipping_address2,shipping_city,shipping_state_province,shipping_country,shipping_postal_code,shipping_phone,items
00,000000,Authorized,0000-00-00 00:00:00,i#me.ca,$00.00,$00.00,Basic Shipping,$0.00,Me,Initial,123 Some Person Street,,Personville,Prov/State,Country,postal,,test,test,test,test,test,test,test,,test,test,test,test,,item name|item price|item quantity
01,000000,Authorized,0000-00-00 00:00:00,i#me.ca,$00.00,$00.00,Basic Shipping,$0.00,Me,Initial,123 Some Person Street,,Personville,Prov/State,Country,postal,,test,test,test,test,test,test,test,,test,test,test,test,,item name|item price|item quantity
02,000000,Authorized,0000-00-00 00:00:00,i#me.ca,$00.00,$00.00,Basic Shipping,$0.00,Me,Initial,123 Some Person Street,,Personville,Prov/State,Country,postal,,test,test,test,test,test,test,test,,test,test,test,test,,item name|item price|item quantity
03,000000,Authorized,0000-00-00 00:00:00,i#me.ca,$00.00,$00.00,Basic Shipping,$0.00,Me,Initial,123 Some Person Street,,Personville,Prov/State,Country,postal,,test,test,test,test,test,test,test,,test,test,test,test,,item name|item price|item quantity
04,000000,Authorized,0000-00-00 00:00:00,i#me.ca,$00.00,$00.00,Basic Shipping,$0.00,Me,Initial,123 Some Person Street,,Personville,Prov/State,Country,postal,,test,test,test,test,test,test,test,,test,test,test,test,,item name|item price|item quantity|item name|item price|item quantity
The purpose here is that my client can download a .CSV directly from the store system (rather than its default .XML) - deal with it in excel as they need to process their orders, and then upload that .CSV back into the store - where it will automatically convert to XML formed like I have shown above.
Since .CSV is a flat format what I did was condense the items XML into a simple .CSV string where each value is delimited by a | which will not be used in any of our markup text on the site. As such item name|item price|item quantity
Here is my code which attempts to achieve this, I come close but I am having some wonky behaviour with the output. It throws an undefined offet error on the noted line $itemvalue = $doc->createTextNode($irow[$g]); (as if the loop is running too many times) and also does not produce the expected output.
function contains($substring, $string) {
$pos = strpos($string, $substring);
if($pos === false) {
// string needle NOT found in haystack
return false;
}
else {
// string needle found in haystack
return true;
}
}
function csv2xml($csvData) {
$outputFilename = 'test.xml';
// Open csv to read
$input = fopen($csvData, 'rt');
// Get the headers of the file
$headers = fgetcsv($input);
// Create a new dom document with pretty formatting
$doc = new DomDocument();
$doc->formatOutput = true;
// Add a root node to the document
$root = $doc->createElement('orders');
$root = $doc->appendChild($root);
while (($row = fgetcsv($input)) !== FALSE) {
$container = $doc->createElement('order');
foreach ($headers as $i => $header)
{
//set temp file name here
$tempFile = "temp.csv";
//prepare mockCSV
$mockCSV = "";
$mockCSV .= "item_name,item_price,item_quantity";
$mockCSV .= "\n";
//check if current property has items data with |
if (contains("|", $row[$i])) {
//if it does create array of data
$item_arr = explode("|", $row[$i]);
//create header for 'items' node
$child = $doc->createElement($header);
$child = $container->appendChild($child);
//count for items
$count = 0;
foreach($item_arr as $k => $item) {
$mockCSV .= trim($item) . ",";
if($count == 2) {
// Trim off the extra comma
$mockCSV = trim($mockCSV, ',');
// Add an LF
$mockCSV .= "\n";
}
$count++;
}
// Trim off the extra comma
$mockCSV = trim($mockCSV, ',');
// Add an LF
$mockCSV .= "\n";
//put mock CSV data in temp file
$f = fopen($tempFile, "w");
fwrite($f, $mockCSV);
fclose($f);
//get data from temp file
$iteminput = fopen($tempFile, 'rt');
//get headers from temp file
$itemheaders = fgetcsv($iteminput);
while (($irow = fgetcsv($iteminput)) !== FALSE) {
$itemchild = $doc->createElement('item');
foreach($itemheaders as $g => $itemheader) {
$subchild = $doc->createElement($itemheader);
$subchild = $itemchild->appendChild($subchild);
$itemvalue = $doc->createTextNode($irow[$g]); /* OFFSET HAPPENS HERE */
$itemvalue = $subchild->appendChild($itemvalue);
}
}
$itemchild = $child->appendChild($itemchild);
}
else {
$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);
}
echo csv2xml("test.csv");
?>
The expected output should be the same as the XML structure I posted above, but instead it is doing this:
<orders>
<order>
<order_id>38</order_id>
<order_number>000015</order_number>
<order_status>Authorized</order_status>
<order_date>0000-00-00 00:00:00</order_date>
<customer_email>test#someemail.ca</customer_email>
<order_amount>$96.00</order_amount>
<base_order_amount>$96.00</base_order_amount>
<shipping_type>Basic Shipping</shipping_type>
<shipping_price> $0.00</shipping_price>
<billing_first_name>Name</billing_first_name>
<billing_last_name>B</billing_last_name>
<billing_address1>PO / Add</billing_address1>
<billing_address2></billing_address2>
<billing_city>Town</billing_city>
<billing_state_province>province</billing_state_province>
<billing_country>Canada</billing_country>
<billing_postal_code>postal code</billing_postal_code>
<billing_phone></billing_phone>
<emt_quest>test</emt_quest>
<emt_answ>test</emt_answ>
<emt_answ_conf>test</emt_answ_conf>
<shipping_first_name>Name</shipping_first_name>
<shipping_last_name>B</shipping_last_name>
<shipping_address1>PO / Add</shipping_address1>
<shipping_address2></shipping_address2>
<shipping_city>Town</shipping_city>
<shipping_state_province>province</shipping_state_province>
<shipping_country>Canada</shipping_country>
<shipping_postal_code>postal code</shipping_postal_code>
<shipping_phone></shipping_phone>
<items>
<item>
<item_name></item_name>
<item_price></item_price>
<item_quantity></item_quantity>
</item>
</items>
</order>
And not putting the values in for some of the fields. Also it does not repeat for double product entries as shown whose source .CSV field looks like this item name|item price|item quantity|item name|item price|item quantity
This is my problem, I can't seem to handle the pipe delimited field properly it doesn't output as expected. In an earlier version of the code I got all the data, but it did not create separate 'item' nodes.
Any help is much appreciated, at this point I think its something simple and I just need another pair of eyes on the subject.
More to the point I am using very patchy code here I feel, I am out of practice with .PHP - I feel there must be some sort of logic problem with how I am going about this - my way can work but there must be a more streamlined method. If anyone could tell me what that is - that's the answer I'm really looking for.
TL:DR starts here
I am trying to convert .CSV data into structured .XML data using pipe delimiting for the second generation and third generation XML children
Only one field in my source .CSV file 'items' contains such information - all other items are single key single entry the data looks like this item name|item price|item quantity|item name|item price|item quantity
So what I do is check for | inside of the .CSV string which is currently being ran through the loop and if it is detected, I use explode() to create an array of what was in there.
I've tried recreating a mock CSV file and putting it in a temp directory to place this information in and then using basic CSV to XML which does work in my program to place that data into the XML Dom Document
Expected output:
<items>
<item>
<item_name>Sample Item</item_name>
<item_price>$8.00</item_price>
<item_quantity>12</item_quantity>
</item>
<item>
<item_name>Sample Item 2</item_name>
<item_price>$8.00</item_price>
<item_quantity>12</item_quantity>
</item>
</items>
Output I am getting:
<items>
<item>
<item_name></item_name>
<item_price></item_price>
<item_quantity></item_quantity>
</item>
</items>
A lot of info I need to get out there to properly illustrate the issue but my problem is simple - how can I achieve the output I want.
Let me backup and offer a routine for CSV to XML first, then take care of the piped elements.
Some comments:
I prefer SimpleXML over DOM for its ease of use, so I'll use it in the example. Of course, it can be done with DOM as well.
I'll make use of str_getcsv() instead of fgetcsv() to be able to create a working example online.
basic CSV to XML
// XML: set up object
$xml = simplexml_load_string("<orders/>");
// CSV: assume CSV in $c, get it as a whole
$csv = str_getcsv($c, "\n");
// CSV: separate 1st row with field names from the following rows
$names = str_getcsv(array_shift($csv));
// CSV: parse row by row
foreach ($csv as $row) {
// CSV: combine names as keys => data as values
$row = array_combine($names, str_getcsv($row));
// XML: create new <order>
$xml_order = $xml->addChild("order");
// CSV: parse a single row
foreach ($row as $key => $value) {
// *****
// XML: create field as child of <order>
$xml_order->addChild($key, $value);
// *****
}
}
handle piped elements
the following code replaces the lines between // ***** above
// CSV: check for pipes, attention use strict comparison ===
if (strpos($value, "|") === false) {
// XML: no pipe, create node as a child of <order>
$xml_order->addChild($key, $value);
} else {
// CSV: pipe present, split up data
$csv_items = str_getcsv($value,"|");
// XML: create <items> node
$xml_items = $xml_order->addChild($key);
// CSV: iterate over $csv_items, each 3 elements = 1 row
// chop row after row
while (!empty($csv_items)) {
// XML: create <item> node as child of <items>
$xml_item = $xml_items->addChild("item");
// XML: create children of <item> node
$xml_item->addChild("item_name", array_shift($csv_items));
$xml_item->addChild("item_price", array_shift($csv_items));
$xml_item->addChild("item_quantity", array_shift($csv_items));
}
}
combine code without comments
$xml = simplexml_load_string("<orders/>");
$csv = str_getcsv($c, "\n"); // assume CSV in $c
$names = str_getcsv(array_shift($csv));
foreach ($csv as $row) {
$row = array_combine($names, str_getcsv($row));
$xml_order = $xml->addChild("order");
foreach ($row as $key => $value) {
if (strpos($value, "|") === false)
$xml_order->addChild($key, $value);
else {
$csv_items = str_getcsv($value,"|");
$xml_items = $xml_order->addChild($key);
while (!empty($csv_items)) {
$xml_item = $xml_items->addChild("item");
$xml_item->addChild("item_name", array_shift($csv_items));
$xml_item->addChild("item_price", array_shift($csv_items));
$xml_item->addChild("item_quantity", array_shift($csv_items));
}
}
}
}
see it working: https://eval.in/368945

simplexml_load_file omitting 00 from xml to csv

I have an XML
Sample:
<?xml version="1.0" encoding="utf-8"?>
<StockValues>
<Product>
<Product_Code>00380</Product_Code>
<Available_Stock>200</Available_Stock>
<Due_Date>2013-10-13</Due_Date>
</Product>
<Product>
<Product_Code>00429</Product_Code>
<Available_Stock>200</Available_Stock>
<Due_Date>2013-11-14</Due_Date>
</Product>
<Product>
<Product_Code>00495</Product_Code>
<Available_Stock>200</Available_Stock>
<Due_Date>N/A</Due_Date>
</Product>
<Product>
<Product_Code>0122</Product_Code>
<Available_Stock>200</Available_Stock>
<Due_Date>N/A</Due_Date>
</Product>
<Product>
<Product_Code>0190</Product_Code>
<Available_Stock>200</Available_Stock>
<Due_Date>2013-10-16</Due_Date>
</Product>
<Product>
<Product_Code>052A</Product_Code>
<Available_Stock>200</Available_Stock>
<Due_Date>N/A</Due_Date>
</Product>
<Product>
<Product_Code>052B</Product_Code>
<Available_Stock>200</Available_Stock>
<Due_Date>2013-10-09</Due_Date>
</Product>
<Product>
<Product_Code>052BK</Product_Code>
<Available_Stock>200</Available_Stock>
<Due_Date>2013-09-28</Due_Date>
</Product>
I am using simplexml_load_file to convert to a CSV. It works great but 2 problems. Firstly my product codes starting with 00 lose the 00 in generating CSV. Therefore I somehow need to keep this is as a text field.
Secondly, I would like to put column headings in here also.
This is the code I have adapted so far:
<?php
$filename='test.csv';
if (! file_exists($filename))
{
echo "There's no test file";
}
else
{
echo "There's 1a test file !";
unlink($filename);
}
echo '<br />';
if( ! $xml = simplexml_load_file('1feed2.xml') )
{
echo 'unable to load XML file';
}
else
{
foreach( $xml as $product_record )
{
$prodarray = "\"$product_record->Product_Code\"".","."$product_record->Available_Stock".",END\n";
echo $prodarray;
//echo '<br />';
file_put_contents($filename,$prodarray,FILE_APPEND);
echo "line written <br />";
}
}
$handle = fopen($filename, "rb");
$contents = fread($handle, filesize($filename));
fclose($handle);
print $contents;
?>
Does anyone know what I can do to fix this?
It currently generates a CSV which is great but just missing the above bits.
Let's assume that you need to add 01, 02 and 03 values in your csv file.
While creating your csv, if you just pass 01,02,03 to the csv file the 0 value won't be displayed when you open the csv file.
To solve this problem just append the file like '01,'02,'03. And the zeros will be displayed when you open the file.
Just remember to add ' character before the column value.
Edit
You haven't mentioned if the column names are fixed or whether it depends on your xml.
I'll try to answer this on the assumption that your column names don't change.
Create a function which appends your data to a csv file. (Although this is not necessary.)
function addRowToCsv($data, $filename){
file_put_contents($filename,$data,FILE_APPEND);
}
In order to add the column names just call the function before the foreach loop.
addRowToCsv("Product Code, Available Stock, Status\n");
See the below updated code.
<?php
$filename='test.csv';
if (! file_exists($filename))
{
echo "There's no test file";
}
else
{
echo "There's 1a test file !";
unlink($filename);
}
echo '<br />';
$xml = simplexml_load_file('1feed2.xml');
//avoid unnecessary else and elseif statments.
if(!$xml){
echo 'unable to load XML file';
exit;
}
//adding column names
addRowToCsv("Product Code, Available Stock, Status\n");
foreach($xml as $product_record){
$product_code = (int) $product_record->Product_Code;
$available_stock = (int) $product_record->Available_Stock;
//Add ' character before the column value
$csv_line = "'$product_code,'$available_stock,END\n";
addRowToCsv($csv_line);
}
$handle = fopen($filename, "rb");
if($handle){
$contents = fread($handle, filesize($filename));
fclose($handle);
print $contents;
}
function addRowToCsv($data, $filename){
file_put_contents($filename,$data,FILE_APPEND);
}
?>

Large XML file Parsing Chunk data Filetering in PHP

I have a large XML file more than 100 MB. I am reading the file in chunks like this
$fp = fopen('large.xml', 'r');
while ($data = fread($fp, 4096)) {
The format of XML is like this
<PersonalInfo>
<UserDetail>
<FirstName>ABC</FirstName>
<Occupation>Student</Occupation>
<DateOfBirth>08/14/1999</DateOfBirth>
</UserDetail>
<CaseDetail>....</CaseDetail>
<TransactionDetail>....</TransactionDetail>
</PersonalInfo>
<PersonalInfo>
<UserDetail>
<FirstName>XYZ</FirstName>
<Occupation>Student</Occupation>
<DateOfBirth>04/25/1991</DateOfBirth>
</UserDetail>
<CaseDetail>....</CaseDetail>
<TransactionDetail>.....</TransactionDetail>
</PersonalInfo>
<PersonalInfo>
<UserDetail>
<FirstName>DEF</FirstName>
<Occupation>Teacher</Occupation>
<DateOfBirth>05/12/1984</DateOfBirth>
</UserDetail>
<CaseDetail>....</CaseDetail>
<TransactionDetail>...</TransactionDetail>
</PersonalInfo>
I want to just include those records where the Occupation TAG is "Student" and write those results to a CSV file.
I have tried the preg_match as
preg_match( "/\(.*?)\</PersonalInfo>/s", $data, $match );
to select the Tags and then look into $match but it is returning double values(repetition).
First check if your xml is valid with the help of following link :
http://www.xmlformatter.net/
If your xml is valid then do following :
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = true;
#$dom->load('large.xml');
$tags = $dom->getElementsByTagName('PersonalInfo');
foreach ($tags as $destination) {
foreach($destination->childNodes as $child) {
if ($child->textContent == "Student") {
echo "Write code to create csv file";
}
}
}

Categories