CSV to XML Conversion
I needed a tool to convert a pretty large file from CSV to XML for a project for work. I looked around for a ready-made one in C++ and couldn’t find it. I looked for a web one and couldn’t find one. So I did what any respectable programmer does. I made my own. I tried to scratch something together in C++, but that gave me all sorts of grief. It probably doesn’t help that I haven’t had to deal with simple file I/O since college. Frustrated, I turned to my friend PHP.
If you would like to see the final result, see the Demo page.
I used 4 PHP files to make this work:
- csvtoxml.php – This is the main entry point where the user browses for a file to upload and enters some parameters.
- upload_file.php – This is the code that uploads the selected file to a directory. lets the user select the output format, and heads to the next PHP file for processing.
- xmloutput.php – This does what you’d expect – it generates the xml output based on the headers of the CSV and the parameters. It deletes the original file.
- xmlDownload.php – If the user selected to download the XML file, this is the page that does the dirty work.
Here is the code for the files:
csvtoxml.php
<?php echo"<form action='upload_file.php' method='post' enctype='multipart/form-data'> <label for='file'>Filename:</label> <input type='file' name='file' id='file' /> <br /><br /> Name at Container Level: <input type='text' name='container' /> <br /><br /> Name at Row Level: <input type='text' name='rows' /> <br /><br /> Schema Filename: <input type='text' name='schema' /> <br /><br /> <input type='radio' name='testnozzle' value='nonozzle' /> Run this using normal parameters<br /> <input type='radio' name='testnozzle' value='nozzle' /> Run this using Test Nozzle CSV Parameters <br /><br /> <input type='submit' value='Submit'/> </form>"; ?>
upload_file.php
<?php // A little preformatting to block unwanted filetypes $allowedExtensions = array("csv"); foreach ($_FILES as $file) { if ($file['tmp_name'] > '') { if (!in_array(end(explode(".", strtolower($file['name']))), $allowedExtensions)) { die($file['name'].' is an invalid file type!<br/>'. '<a href="javascript:history.go(-1);">'. '<< Go Back</a>'); } } } $fileloc = $_FILES['uploadedfile']['name']; echo "Your file is located at " . $fileloc . "\n"; if ($_FILES["file"]["error"] > 0) { echo "Return Code: " . $_FILES["file"]["error"] . "<br />"; } else { echo "Upload: " . $_FILES["file"]["name"] . "<br />"; echo "Type: " . $_FILES["file"]["type"] . "<br />"; echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />"; echo "Temp file: " . $_FILES["file"]["tmp_name"] . "<br />"; if (file_exists("upload/" . $_FILES["file"]["name"])) { echo $_FILES["file"]["name"] . " already exists. "; } else { move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"]); echo "Stored in: " . "upload/" . $_FILES["file"]["name"]; } } $filename = "upload/" . $_FILES["file"]["name"]; $level1 = $_REQUEST['container']; $level2 = $_REQUEST['rows']; $schema = $_REQUEST['schema']; $nozzle = $_REQUEST['testnozzle']; echo "<form action='xmloutput.php' method='post'> <input type='hidden' name='filename' value=$filename> <input type='hidden' name='containtitle' value=$level1> <input type='hidden' name='rowtitle' value=$level2> <input type='hidden' name='schemastr' value=$schema> <input type='hidden' name='nozzle' value=$nozzle> <br /> <input type='radio' name='output' value='display' /> Display the XML<br /> <input type='radio' name='output' value='file' /> Save the XML to File <br /><br /> <input type='submit' value='Submit'/> <br /> <em>This may take some time for large files</em>"; ?>
xmloutput.php
<?php function csv2xml($file, $container = 'data', $rows = 'row',$schema,$testnozzle) { $r = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"; $r .= "Export xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"{$schema}\"\n"; $r .= "<{$container}>\n"; $row = 0; $cols = 0; $titles = array(); $firstrun = true; $handle = @fopen($file, 'r'); if (!$handle) return $handle; while (($data = fgetcsv($handle, 1000, ',')) !== FALSE) { if (!$cols) $cols = count($data); // if this is a nozzle test csv for work if($testnozzle == 'nozzle') { $index = $data[0]; $color = $data[1]; $noznum = $data[2]; // if the noznum is 0, we're starting a new printhead, so output new tag if($noznum == '0') { if($firstrun == false) { $r .= "\t</Color>\n"; } else { $r .= "\t<Barcode>L0123456789</Barcode>\n"; } $r .= "\t<Color ID=\"{$color}\" NumCols=\"41\" ColTypes=\"ISIFFFFFFFFFFFFFFFFFFIFFFFFFFFFFFIFIFFFIFFI\">\n"; $firstrun = false; } // for every row of data, put the nozzle number in the tag if ($row > 0) $r .= "\t\t<{$rows} ID=\"{$noznum}\">\n"; for ($i = 0; $i < $cols; $i++) { if ($row == 0) { $titles[$i] = $data[$i]; continue; } $r .= "\t\t\t<{$titles[$i]}>"; $r .= $data[$i]; $r .= "</{$titles[$i]}>\n"; } if ($row > 0) $r .= "\t\t</{$rows}>\n"; $row++; } else { if ($row > 0) $r .= "\t\t<{$rows}>\n"; for ($i = 0; $i < $cols; $i++) { if ($row == 0) { $titles[$i] = $data[$i]; continue; } $r .= "\t\t<{$titles[$i]}>"; $r .= $data[$i]; $r .= "</{$titles[$i]}>\n"; } if ($row > 0) $r .= "\t</{$rows}>\n"; $row++; } } fclose($handle); if (!unlink($file)) { echo ("Error deleting $file"); } if($testnozzle == 'nozzle') { $r .= "\t</Color>\n"; } $r .= "</{$container}>"; return $r; } header("Content-type: text/xml"); $filename = $_REQUEST['filename']; $level1 = $_REQUEST['containtitle']; $level2 = $_REQUEST['rowtitle']; $schema = $_REQUEST['schemastr']; $testnozzle = $_REQUEST['nozzle']; $output = $_REQUEST['output']; $xml = csv2xml($filename,$level1,$level2,$schema,$testnozzle); //$File = $filename; $File .= "newFromCSV.xml"; $Handle = fopen($File, 'w'); fwrite($Handle, $xml); fclose($Handle); if($output == "file") { header('Location: xmlDownload.php'); } else { echo($xml); } ?>
xmlDownload.php
<?php // We'll be outputting XML header('Content-type: application/xml'); // It will be called downloaded.xml header('Content-Disposition: attachment; filename="download.xml"'); // The XML source is in original.xml readfile('./newFromCSV.xml'); ?>
If I get some downtime (HA!) I’ll try to go in and add some comments later.