Getting Cell as String in PHPExcel by column and row - string

I am trying to read a cell with possible trailing zeros as a string instead of numeric (which strips off leading zeros). The cell is read by integer column/row as below instead of column string as this answer has.
initial code
$instReader = $reader->load($this->file);
$sheet = $instReader->getSheet(0);
I tried modifying this from:
$keyCell = $sheet->getCellByColumnAndRow(1,5);
to:
$sheet->setCellValueExplicitByColumnAndRow(1,5, PHPExcel_Cell_DataType::TYPE_STRING);
$keyCell = $sheet->getCellByColumnAndRow(1,5);
the former gives 1407 for $keyCell instead of 01407
the latter gives "s" or ""
how do I treat the cell as string before calling getCellByColumnAndRow and using only integer values for column and row.
(BTW, if this can be done once for an entire column instead of each time for each individual cell that would be better)

$keyCell = $sheet->getCellByColumnAndRow(1,5)->getValue();
Will read the cell data in the format that it's actually stored by Excel, you can't arbitrarily change that or tell PHPExcel to read it as a different datatype.
However, if the cell has formatting applied, then you can use
$keyCell = $sheet->getCellByColumnAndRow(1,5)->getFormattedValue();
instead, and this will return the data as a string, with whatever format mask was defined in the Excel spreadsheet

Same issue for me. I become crazy.
Tried to set
$objReader->setReadDataOnly(true);
wasn't working
tried
$sheet->getCellByColumnAndRow(4,$row)->getValue()
because normaly display text as raw => doesn't working.
So last I change code in library. Edit file named DefaultValueBinder.php
Search for dataTypeForValue function and set this :
} elseif (is_float($pValue) || is_int($pValue)) {
return PHPExcel_Cell_DataType::TYPE_STRING;//TYPE_NUMERIC patch here;
} elseif (preg_match('/^\-?([0-9]+\\.?[0-9]*|[0-9]*\\.?[0-9]+)$/', $pValue)) {
return PHPExcel_Cell_DataType::TYPE_STRING;//TYPE_NUMERIC patch here;
So now return numbers with 0

Related

How can we include the cell formula while export to excel from .rdlc

In my rdlc report have following columns
SlNo, Item, Uom, Qty, Rate, Amount
Here the Amount field is a formula (Rate*Qty)
The report is working fine, and when i export to excel also displaying the values are correctly.
But my problem is, after export to excel, when i change the Qty or Rate columns in excel file the Amount is not get changed automatically, because the formula is missing in the excel cell.
How can we include the formula in Amount column while export to excel from .rdlc?
I'm afraid that this required behaviour isn't really possible by just using the rdlc rendering.
In my search I stumbled upon this same link that QHarr posted: https://social.msdn.microsoft.com/Forums/en-US/3ddf11bf-e10f-4a3e-bd6a-d666eacb5ce4/report-viewer-export-ms-report-data-to-excel-with-formula?forum=vsreportcontrols
I haven't tried the project that they're suggesting but this might possibly be your best solution if it works. Unfortunately I do not have the time to test it myself, so if you test this please share your results.
I thought of the following workaround that seems to work most of the times, but isn't really that reliable because the formula sometimes gets displayed as full-text instead of being calculated. But I guess this could be solved by editing the excel file just after being exported, and changing the cell properties of this column containing the formula or just triggering the calculate.
Using the built-in-field Globals!RenderFormat.Name you can determine the render mode, this way you can display the result correctly when the report is being rendered to something different than Excel. When you export to Excel, you could change the value of the cell to the actual formula.
To form the formula it's self you'll need to figure this out on your own, but the RowNumber(Scope as String) function can be of use here to determine the row number of your cells.
Here is a possible example for the expression value of your amount column
=IIF(Globals!RenderFormat.Name LIKE "EXCEL*", "=E" & Cstr(RowNumber("DataSet1")+2) & "*F" & Cstr(RowNumber("DataSet1")+2) ,Fields!Rate.Value * Fields!Qty.Value )
Now considering that this formula sometimes gets displayed as full-text, and you'll probably have to edit the file post-rendering. If it's too complicated to determine which row/column the cell is on, you could also do this post-rendering. But I believe that the above expression should be easy enough to use to get your desired result without having to do much after rendering.
Update: The following code could be used to force the calculation of the formula (post rendering)
var fpath = #"C:\MyReport.xlsx";
using (var fs = File.Create(fpath))
{
var lr = new LocalReport();
//Initializing your reporter
lr.ReportEmbeddedResource = "MyReport.rdlc";
//Rendering to excel
var fbytes = lr.Render("Excel");
fs.Write(fbytes, 0, fbytes.Length);
}
var xlApp = new Microsoft.Office.Interop.Excel.Application() { Visible = false };
var wb = xlApp.Workbooks.Open(fpath);
var ws = wb.Worksheets[1];
var range = ws.UsedRange;
foreach (var cell in range.Cells)
{
var cellv = cell.Text as string;
if (!string.IsNullOrWhiteSpace(cellv) && cellv.StartsWith("="))
{
cell.Formula = cellv;
}
}
wb.Save();
wb.Close(0);
xlApp.Quit();

PHPExcel prevent calculating formula

I'm trying to convert a CSV file to a XLSX file using PHPExcel library. Once the csv file is read into PHPExcel object and before saving it as a xlsx file, I recalculate and set column widths based on relevant column content.
$objReader = PHPExcel_IOFactory::createReader('CSV');
$objPHPExcel = $objReader->load("test.csv");
$activesheet = $objPHPExcel->getActiveSheet();
$lastColumn = $activesheet->getHighestColumn(); // get last column with data
$lastColumn++;
for ($column = 'A'; $column != $lastColumn; $column++) { // for each column until last
$activesheet->getColumnDimension($column)->setAutoSize(true); // set autowidth
}
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
$objWriter->save("downloads/test.xls");
with bit of a research i found that if there are any formulas in the file, call to setAutoSize() calculates the value for them to make use when calculating the column width.
My problem is that some of my csv files contain values that begins with = (equal sign) which are not formulas. for ex. cell values like '===='. This causes above code to throw an error PHPExcel_Calculation_Exception Formula Error: An unexpected error occured.
Since I know that any of my input csv files cannot contain formulas, is there a way to prevent PHPExcel calculating values for cells which contain values beginning with = sign?
After research and given suggestions I ended up iterating through all the cells and rewriting cell values (beginning with = sign), to prevent PHPExcel considering them as formulas. setCellValueExplicit() method instructs PHPExcel to not consider the cell value as a formula in this case.
foreach ($objPHPExcel->getWorksheetIterator() as $worksheet) {
foreach ($worksheet->getRowIterator() as $row) {
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(true);
foreach ($cellIterator as $cell) {
if (preg_match( '/^=/', $cell->getValue())) {
$cellcoordinate = $cell->getCoordinate();
$worksheet->setCellValueExplicit($cellcoordinate,$worksheet->getCell($cellcoordinate));
}
}
}
}
It's painful, but couldn't find a better solution.

phpexcel reading an excel file decimal numbers are read incorrectly

I've got the value '9,2' (dutch notation of '9.2') within a cell of a .xlsx file, the cell has a 'general' number format. Also the value in the upper bar where you also view formulas says '9,2' When I read this cell with PHPExcel with ->getValue() I get '9,199999999999999'.
This is my code:
$oPhpReader = PHPExcel_IOFactory::createReader($sFileType);
$aWorksheetNames = $oPhpReader->listWorksheetNames($sFileName);
$oPhpReader->setReadDataOnly(true);
$oPhpReader->setLoadSheetsOnly($aWorksheetNames[0]);
$oPhpExcel = $oPhpReader->load($sFileName);
$oWorksheet = $oPhpExcel->getActiveSheet();
$oCell = $oWorksheet->getCellByColumnAndRow($iCol,$iRow);
$sTempValue = $oCell->getValue();
This is the way I solved my problem now. Though I do not think this is a very neat solution, it is probably the only way.
I just figured I will never get numbers with more than 12 digits, only when PHPExcel get them wrong. So I round all my floats to 12 digit using number_format:
if ((is_numeric($sTempValue))&&(strpos($sTempValue,'.')))
{
$sTempValue = rtrim(rtrim(number_format($sTempValue,12,',',''),'0'),',');
}

Opening excel file prompts a message box "content recovery of the workbook"

While I'm trying to open excel file a message box is prompting like "We found a problem with some content in file name. Do you want us to try to recover as much as we can? If you trust the source of this workbook, click Yes.". What actually done is i have a excel template designed and copying the file to another file and created temp file I'm inserting data to temp file using OPEN XML and data is getting from the database.
i have tried the solutions provided in the net but those fixes are not resolving my issue.My excel is 2010
Anyone solution provided is much appreciated.
I had this problem. It was caused by the way I was storing numbers and strings in cells.
Numbers can be stored simply using cell.CellValue = new CellValue("5"), but for non-numeric text, you need to insert the string in the SharedStringTable element and get the index of that string. Then change the data type of the cell to SharedString, and set the value of the cell to the index of the string in the SharedStringTable.
// Here is the text I want to add.
string text = "Non-numeric text.";
// Find the SharedStringTable element and append my text to it.
var sharedStringTable = document.WorkbookPart.GetPartsOfType<SharedStringTablePart>().First().SharedStringTable;
var item = sharedStringTable.AppendChild(new SharedStringItem(new Text(text)));
// Set the data type of the cell to SharedString.
cell.DataType = new EnumValue<CellValues>(CellValues.SharedString);
// Set the value of the cell to the index of the SharedStringItem.
cell.CellValue = new CellValue(item.ElementsBefore().Count().ToString());
This is explained in the documentation here: http://msdn.microsoft.com/en-us/library/office/cc861607.aspx
Another few cases that can cause this type of error:
Your sheet name is longer than 31 characters
You have invalid characters in sheet name
You have cells with values longer than 32k
The issue is due to using
package.Save();
and
package.GetAsByteArray();
at the same time
when we call
package.GetAsByteArray();
it will do following operations
this.Workbook.Save();
this._package.Close();
this._package.Save(this._stream);
Hence, removing
package.Save();
will solve this problem "We found a problem with some content in file name. Do you want us to try to recover as much as we can? If you trust the source of this workbook, click Yes."
Another possible cause could be exceeded maximum number of cell styles.
You can define:
up to 4000 styles in a .xls workbook
up to 64000 styles in a .xlsx workbook
In this case you should re-use the same cell style for multiple cells, instead of creating a new cell style for every cell.
I added the right cellReference and fixed this issue for me:
string alpha = "ABCDEFGHIJKLMNOPQRSTUVQXYZ";
for (int colInx = 0; colInx < reader.FieldCount; colInx++)
{
AppendTextCell(alpha[colInx] + "1", reader.GetName(colInx), headerRow);
}
private static void AppendTextCell(string cellReference, string cellStringValue, Row excelRow)
{
// Add a new Excel Cell to our Row
Cell cell = new Cell() { CellReference = cellReference, DataType = new EnumValue<CellValues>(CellValues.String) };
CellValue cellValue = new CellValue();
cellValue.Text = cellStringValue.ToString();
cell.Append(cellValue);
excelRow.Append(cell);
}
Same warning but the problem with me was that I was using a client input (name of wave) as sheet name for the file and when date was presented within the name, the character '/' used as date part separator was causing the issue.
I think Microsoft need to provide a better error log to save people time investigate such minor issues. Hope my answer will save someone else's time.
The issue was due to storing a string in the cell directly using cell.CellValue = new CellValue("Text"). It is possible to store numbers like this but not string. For string, define data type as string before assigning the text using Cell.DataType = CellValues.String;

Export Excel : Avoid stripping the leading zeros

I am Export a data to Excel Sheet in C#.Net. There i am having column which has the data like "00123450098". The data is exported without the first zero's. I want to show the data as it is.
Here is my export excel code.
string style = #"<style> .text { mso-number-format:\#; } </style> ";
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.AddHeader(
"content-disposition", string.Format("attachment; filename={0}", fileName));
HttpContext.Current.Response.ContentType = "application/ms-excel";
HtmlForm frm = new HtmlForm();
...................
...................
table.RenderControl(htw);
HttpContext.Current.Response.Write(style);
//render the htmlwriter into the response
HttpContext.Current.Response.Write(sw.ToString());
HttpContext.Current.Response.End();
While exporting to excel, adding \t before the value being inserted will solve the problem.
Eg:
string test = "000456";
string insertValueAs = "\t" + test;
The string test would then be considered as a string value and not an integer value. Thus, it would retain the leading zeros.
I have faced the same issue, and above solution worked for me. Hope this post helps!
If exporting to CSV / TSV, put this into each cell containing a textual "number" with leading 0s or (especially) 16+ digits:
="0012345"
..where 0012345 is the number you want to export to that cell.
I wish I could remember where I saw that.
In Excel file, Numbers cell always strips the leading zeros, you can set numbers with leading zeros by following a single quote. i.e.
00123450098 to '00123450098
but then, the format for that cell will changes to text.
If your generated excel file, have any formula, which is include that cell reference as number then it will not work as expected.
I had this problem as well. The solution I came up with was to sneak the leading zeros in using excel's built in char() function. In excel, char() returns the value of the ASCII character code that is passed to it, so char(048) returns 0.
Before exporting to excel, prepend your variable like so...
varName = "=CHAR(048)&" + varName;
I found my answer for this using a combination of StackOverflow link and a blog.
There are excel formatting styles that can be applied to the gridview on rowdatabound. I used those and now my export does not strip the leading zeros.
Below is an example of my code.
ExpenseResultsGrid.RowDataBound += new GridViewRowEventHandler(ExpenseResultsGrid_RowDataBound);
protected void AllQuartersGrid_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{//add this style to prevent truncating leading zeros in fund code during export to excel
e.Row.Cells[2].Attributes.CssStyle.Add("mso-number-format", "\\#");
}
}
While exporting, just add an empty string like "" before the value that is inserted:
string x = "000123";
myWorksheet.Cells[1,1] = "" + x;

Resources