The code below is returning an empty sheets array for at least two different .xlsx files (from the same source), although for other .xls and .xlsx it does return an filled array.
$inputFileType is valid" EXCEL2007", $path is valid and there are sheets in the file. var_dump on $objReader display an object.
Any ideas?
public function listSheets($path)
{
$inputFileType = PHPExcel_IOFactory::identify($path);
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
$sheets = $objReader->listWorksheetNames($path);
return $sheets;
}
Update
The function listWorkBookInfo also fails for the same files that listWorkBookNames fails.
The workbook xml are different. Theses xmk are outut from
$this->getFromZipArchive($zip, "{$rel['Target']}")
PHPExcel likes
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:ignorable="x15" xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"><fileversion appname="xl" lastedited="6" lowestedited="4" rupbuild="14420"><workbookpr defaultthemeversion="124226"><mc:alternatecontent xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"><mc:choice requires="x15"><x15ac:abspath url="W:\Rates\carrier\" xmlns:x15ac="http://schemas.microsoft.com/office/spreadsheetml/2010/11/ac"></x15ac:abspath></mc:choice></mc:alternatecontent><bookviews><workbookview xwindow="0" ywindow="0" windowwidth="21570" windowheight="8145"></workbookview></bookviews><sheets><sheet name="Rates" sheetid="1" r:id="rId1"><sheet name="Data" sheetid="4" state="hidden" r:id="rId2"></sheet></sheet></sheets><calcpr calcid="152511"></calcpr></workbookpr></fileversion></workbook>
and PHPExcel does not likes
<x:workbook xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><x:fileversion appname="xl" lastedited="5" lowestedited="5" rupbuild="9303"><x:workbookpr defaultthemeversion="124226"><x:bookviews><x:workbookview xwindow="360" ywindow="45" windowwidth="10515" windowheight="7245"></x:workbookview></x:bookviews><x:sheets><x:sheet name="International Destinations" sheetid="5" r:id="rId1"><x:sheet name="National Destinations" sheetid="4" r:id="rId2"></x:sheet></x:sheet></x:sheets><x:calcpr calcid="145621"></x:calcpr></x:workbookpr></x:fileversion></x:workbook>
Related
I'm using ExcelDataReader for reading .xlsx, .xls, .csv file while reading it treats everything as strings so a #N/A or #value! is also treated as a string and gives an exception when I try to do computation on them.
FileStream stream = File.Open(strFilePath, FileMode.Open, FileAccess.Read);
//Reading from a binary Excel file ('97-2003 format; *.xls)
string extension = System.IO.Path.GetExtension(strFilePath).ToLower();
IExcelDataReader excelReader;
if (extension.Equals(".csv"))
{
excelReader = ExcelReaderFactory.CreateCsvReader(stream);
}
else if (extension.Equals(".xls"))
{
excelReader = ExcelReaderFactory.CreateBinaryReader(stream);
}
else
{
excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream);
}
//...
//DataSet - The result of each spreadsheet will be created in the result.Tables
//DataSet - Create column names from first row
DataSet result = excelReader.AsDataSet(new ExcelDataSetConfiguration()
{
ConfigureDataTable = (_) => new ExcelDataTableConfiguration()
{
UseHeaderRow = true
}
});
excelReader.Close();
return result.Tables[sheetno];
This is the code I use for importing excel file. How can it be modified to read #N/A or #value! as 0 or NULL?
This is a bug in ExcelDataReader's XLSX parser and needs a code fix in the library.
Bug is tracked here:
https://github.com/ExcelDataReader/ExcelDataReader/issues/329
ExcelDataReader with XLS works as expected: it returns NULL for fields with an error.
ExcelDataReader with CSV will likely continue to return the error as a string, because the CSV format does not disambiguate error strings from regular strings.
I create a sheet
$xls = new PHPExcel();
$xls->addSheet('my sheet');
I create an object to read a .csv
$objReader = PHPExcel_IOFactory::createReader('myfile.csv');
$objPHPExcel = $objReader->load($myFileName);
Is there a short way to place all the rows from the csv into the current worksheet?
The worksheet object has fromArray() and toArray() methods, so why not use those?
$xls->getActiveSheet()
->fromArray(
$objPHPExcel->getActiveSheet()->toArray()
);
Otherwise you can iterate over $objPHPExcel->getActiveSheet() reading cells, or rows at a time, then inserting them into $xls->getActiveSheet()
I am trying to extract some sheets in phpexcel as follows (see https://stackoverflow.com/a/10587576/813801 for reference).
$newObjPHPExcel = new PHPExcel();
$newObjPHPExcel->removeSheetByIndex(0); //remove first default sheet
foreach ($sheets as $sheetIndex) {
echo "trying-$sheetIndex\n";
$workSheet = $objPHPExcel->getSheet($sheetIndex);
echo "done-$sheetIndex\n";
$newObjPHPExcel->addExternalSheet($workSheet);
}
(sheets is an array of indexes which are within the bounds of the sheet. I checked with listWorksheetInfo)
If I comment out the the last line $newObjPHPExcel->addExternalSheet($workSheet);
The getSheet method works fine. Otherwise, I get an error:
Fatal error: Uncaught exception 'PHPExcel_Exception' with message 'Your requested sheet index: 2 is out of bounds. The actual number of sheets is 1.' in /Xls/PHPExcel/PHPExcel.php:577
Why should newObjPHPExcel interfere with objPHPExcel?
UPDATE:
I found a workaround which seems to work. not sure why the other version did not work though.
$newObjPHPExcel = new PHPExcel();
$newObjPHPExcel->removeSheetByIndex(0); //remove first default sheet
foreach ($sheets as $sheetIndex) {
echo "trying-$sheetIndex\n";
$workSheet[] = $objPHPExcel->getSheet($sheetIndex);
echo "done-$sheetIndex\n";
}
foreach ($workSheet as $obj)
$newObjPHPExcel->addExternalSheet($obj);
The addExternalSheet() method actually removes the worksheet from the old workbook and moves it to the new one, but your iterator over the old workbook collection of sheets still believes that it contains that worksheet when it no longer does.
In your second "workround" code, you're not removing the sheets from the old workbook until after you've completed iterating over the first loop, you're simply setting an array of pointers to the sheets, then iterating over that array, so the pointer array doesn't care that the sheets are being moved from one workbook to another, they all still exists, so no error.
An alternative might be to use the worksheet iterator against the old workbook, which should update cleanly as the sheets are removed.
This is my code
<?php
if($_POST['submited'])
{
if($_POST['dwnld_query']=="All applicants")
{
$q="select * from es_enquiry";
$result=mysql_query($q);
}
header( "Content-Type: application/vnd.ms-excel" );
header( "Content-disposition: attachment; filename='".$_POST['dwnld_query']."'.xls" );
// print your data here. note the following:
// - cells/columns are separated by tabs ("\t")
// - rows are separated by newlines ("\n")
echo 'RegNo'."\t".'App for class'."\t".'FirstName'."\t".'Middle-Name'."\t".'Last-Name'."\t".'Gender'."\t".'Father Name'."\t".'DOB'."\t".'AGE'."\t".'Child Category'."\t".'Parent Category'."\t".'TC Case'."\t".'Last School Name'."\t".'TC Date'."\t". 'TC No'."\t".'CGPA'."\n";
$tc_case;
$tc_date;
$tc_no;
while($row=mysql_fetch_object($result))
{
if($row->last_school_type=="KV"){$tc_case="Yes";}
else{$tc_case="No";}
if($row->kv_tc_date==" ")
{
$tc_date="-";
}
else
{
$tc_date=$row->kv_tc_date;
}
if($row->kv_tc_no==" ")
{
$tc_no="-";
}
else
{
$tc_no=$row->kv_tc_date;
}
// for example:
echo $row->eq_application_no."\t".$row->eq_class."\t".$row->eq_name."\t".$row->mid_name."\t".$row->last_name."\t".$row->eq_sex."\t".$row->father_name."\t".$row->eq_dob."\t".$row->age."\t".$row->scat_id."\t".$row->parent_cate_id."\t".$tc_case ."\t".$row->eq_prv_acdmic."\t".$tc_date."\t".$tc_no."\t".$row->last_class_cgpa."\n";
}
}
?>
When I download the excel file it shows the Author:Maarten Balliauw, Subject:Office 2007 XLSX Test Document, Title:Office 2007 XLSX Test Document, Categories:Test result file, Tags:office 2007 openxml php. AS you all can see in my code nothing is mentioned about these then from where these are coming and how to change or remove these.
If you were using PHPExcel, these properties are set against the PHPExcel object itself, in the Document Properties, e.g.
$objPHPExcel->getProperties()
->setCreator("Maarten Balliauw")
->setLastModifiedBy("Maarten Balliauw")
->setTitle("PHPExcel Test Document")
->setSubject("PHPExcel Test Document")
->setDescription("Test document for PHPExcel, generated using PHP classes.")
->setKeywords("office PHPExcel php")
->setCategory("Test result file");
But your code isn't using PHPExcel at all; and doesn't even look as though it's creating an Excel file, but simply creating a tab-separated value file by hand (and without even using safer PHP's simpler and safer built-in fputcsv() function)... so it certainly isn't generating a file that is even capable of containing any document properties.
So check what script is really generating what file
I'm using Asp.net to create a csv file that the user can open directly in excel. I want to make it possible to show the download popup and for the user to choose "Open with Excel" and that will open the file in excel.
The code to create the csv:
Response.Clear();
Response.AddHeader("content-disposition", string.Format("attachment; filename={0}.csv", "test"));
Response.ContentType = "text/csv";
Response.Write("Year, Make, Model, Length\n1997, Ford, E350, 2.34\n2000, Mercury, Cougar, 2.38");
Response.End();
Excel needs to understand that "Year", "Make", etc should all be different columns. That doesn't seem to work with the csv I'm creating, everything is just in the same column. It shows up like this:
http://oi54.tinypic.com/2evyb0k.jpg
The only way to get it working with excel is to use the "Text Import Wizard". Then everything shows up in different columns like it should.
As I said what I need is to create a spreadsheet (it doesn't need to be csv), it should just be easy for the user to open in excel or whatever they are using to start working with it. How would you solve this? Thanks!
Not sure why it doesn't work like that - it does for me, but at a minimum try quoting the data:
Response.Write("\"Year\", \"Make\", \"Model\", \"Length\"\n\"1997\", \"Ford\", \"E350\", \"2.34\"\n\"2000\", \"Mercury\", \"Cougar\", \"2.38\"");
Excel can also import XML, google "<?mso-application progid="Excel.Sheet"?>" for the format. Or just save an excel spreadsheet as XML to see an example. Excel XML files can be named ".xls" and it will be able to open them directly.
Finally, you can use NPOI in .NET to manipulate excel spreadsheets in the native format: http://npoi.codeplex.com/
For XML you can also use a wrapper class I wrote that encapsulates this in a simple C# object model: http://snipt.org/lLok/
Here's some pseudocode for using the class:
XlsWorkbook book = new XlsWorkbook();
XlsWorksheet ws = new XlsWorksheet();
ws.Name = "Sheet Name";
XlsRow row;
XlsCell cell;
foreach (datarow in datasource) {
row = new XlsRow();
foreach (datavalue in datarow) {
cell = new XlsCell(datavalue.ToString());
cell.DataType = datavalue is numeric ? DataTypes.Numeric | DataTypes.String;
row.Cells.Add(cell);
}
ws.Rows.Add(row);
}
wkb.Worksheets.Add(ws);
Response.Write(wkb.XmlOutput());
Or just create your own method, here are the basics.
Create the header this way:
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.Append("<?xml version=\"1.0\"?>\n");
sb.Append("<?mso-application progid=\"Excel.Sheet\"?>\n");
sb.Append(
"<Workbook xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\" ");
sb.Append("xmlns:o=\"urn:schemas-microsoft-com:office:office\" ");
sb.Append("xmlns:x=\"urn:schemas-microsoft-com:office:excel\" ");
sb.Append("xmlns:ss=\"urn:schemas-microsoft-com:office:spreadsheet\" ");
sb.Append("xmlns:html=\"http://www.w3.org/TR/REC-html40\">\n");
sb.Append(
"<DocumentProperties xmlns=\"urn:schemas-microsoft-com:office:office\">");
sb.Append("</DocumentProperties>");
sb.Append(
"<ExcelWorkbook xmlns=\"urn:schemas-microsoft-com:office:excel\">\n");
sb.Append("<ProtectStructure>False</ProtectStructure>\n");
sb.Append("<ProtectWindows>False</ProtectWindows>\n");
sb.Append("</ExcelWorkbook>\n");
From there, add to your output string by creating nodes using this basic structure:
<Worksheet ss:Name="SheetName">
<Table>
<Row>
<Cell>
<Data ss:Type="DataType">Cell A1 Contents Go Here</Data>
</Cell>
</Row>
</Table>
</Worksheet>
Within a <Row>, each <Cell> element creates a new column. Add a new <Row> for each spreadsheet row. The DataType for <Data> can be "String" or "Number".