I am using Apache-POI 3.14. I have a need to lock-down a cell to a "Text" format. The data in my cell might be all digits, but it is still considered a string. When I write the cell, I do it like this:
cell.setCellValue("001");
cell.setCellType(Cell.CELL_TYPE_STRING);
When I open the output workbook in Excel, the cell contains the correct value ("001") and it displays with a small green triangle in the corner. Hovering over the exclamation point displays the hover text The number in this cell is formatted as text or preceded by an apostrophe. When I look at the cell formatting (Right-click -> Format cells), the "Category" is displayed as "General". I expected this to be "Text".
The problem arises when a user modifies the value in the cell by entering only digits. Because the "Category" is "General", the value is entered and displayed as a number, removing leading zeroes and right-justified.
How can I achieve the same result as Excel's "Format cells" dialog?
You can try to set the cell-format to text via
DataFormat fmt = wb.createDataFormat();
CellStyle cellStyle = wb.createCellStyle();
cellStyle.setDataFormat(
fmt.getFormat("#"));
cell.setCellStyle(cellStyle);
Note: CellStyles shoudl be re-used for all applicable cells, do not create new ones for every cell.
You could also try to use the "Ignore errors" feature in the .xlsx format, however support for it is not fully done yet, see Issue 46136 and Issue 58641 for some ongoing discussion.
See also this MSDN page for some additional information
For HSSF,
DataFormat fmt = workbook.createDataFormat();
CellStyle textStyle = workbook.createCellStyle();
textStyle.setDataFormat(fmt.getFormat("#"));
sheet.setDefaultColumnStyle(0, textStyle);
It just sets the whole column style as Text and set category as Text .
However, if you are using XSSF format, it doesn't work(I am using Apache Poi 3.15 and didn't work for me).
In this case you have set style to each cell you want to treat as text in addition to above code using:
cell.setCellStyle(textStyle);
Regarding error, you could use
sheet.addIgnoredErrors(new CellRangeAddress(0,9999,0,9999),IgnoredErrorType.NUMBER_STORED_AS_TEXT );
It ignores the NUMBER_STORED_AS_TEXT error for row 0 till 9999 and column 0 till 9999 and you wont see it.
Look like OP was asking for Apache solution. After some searching I found this answer:
HSSFCellStyle style = book.createCellStyle();
style.setDataFormat(BuiltInFormats.getBuiltInFormat("text"));
In this case, I'm using Apache-POI 3.15, and I had the same problem, so I validated the data in my style, I need numbers >0 and strings:
try {
if (Integer.parseInt(field + "") >= 0) {
int valor = Integer.parseInt(field + "");
cell.setCellValue(valor); //Int
}
} catch (NumberFormatException nfe) {
// no int
try {
if (Double.parseDouble(field + "") >= 0) {
double valor = Double.parseDouble(field + ""); //double
cell.setCellValue(valor);
}
} catch (NumberFormatException nfe2) {
cell.setCellValue(field + ""); //String
}
}
For Apache POI 4.0.1 :
XSSFSheet sheet = workbook.createSheet("MySheetName");
sheet.addIgnoredErrors(new CellRangeAddress(0, 9999, 0, 9999), IgnoredErrorType.NUMBER_STORED_AS_TEXT);
Be careful to cast your sheet to org.apache.poi.xssf.usermodel.XSSFSheet and not to org.apache.poi.ss.usermodel.Sheet, otherwise the method addIgnoredErrors wil be unknown.
Related
Java 8 and Apache POI 4.1.x here. I need to:
Read in a template Excel file, that just has a single row of pre-styled header columns
Write a List<Fizz> (POJO list) to a new Excel file that uses that template
I do this because the template Excel has lots of complicated stylings, and so just using an existing one as a template input was much easier than me trying to manually generate the stylings myself via POI and CellUtil.
I have this working perfectly fine like so:
List<Fizz> fizzes = getSomehow();
InputStream inp = this.getClass().getClassLoader().getResource("my-template.xlsx").openStream();
Workbook workbook = WorkbookFactory.create(inp);
Sheet sheet = workbook.getSheetAt(0);
// the header is at row = 0 (0-based rows)
// so start writing the list on the row=1 (1st data/non-header row)
int rowNum = 1;
for (Fizz fizz : fizzes) {
Row nextRow = sheet.createRow(rowNum);
Cell itemNumber = nextRow.createCell(0);
itemNumber.setCellValue(fizz.getItemNumber());
Cell description = nextRow.createCell(1);
description.setCellValue(fizz.getDescription());
rowNum++;
}
// resize the columns appropriately
for (int c = 0; c < 2; c++) {
sheet.autoSizeColumn(c);
}
// export to file system
FileOutputStream fos = new FileOutputStream("some-output.xlsx");
workbook.write(fos);
fos.close();
inp.close();
workbook.close();
Everything works great, with one exception: often the Fizz#description is pretty lengthy, and is sometimes hundreds of characters long. Because there is no use of text wrapping in my code, and because I use autoSizeColumn for all columns, POI is setting the Description column width to the length of the longest-description.
Instead, I now want to stop using autoSizeColumn (I think!) and instead:
Force the output file's (in our case, "some-output.xlsx") Description column width to be the same as the input template file's Description's column. So if the Description column on my-template.xlsx is, say, 54, then I want some-output.xlsx's Description column to also be 54.
If the current row's Fizz description is too long for that width, I want to apply text wrapping so that the column stays fixed (again, in this case, 54) but that the description fits inside of it.
I would like to do this for every column, and ideally, I would like the code to detect what the width is for each column on the template. I say that because I would like to be able to open the template in Excel, change its width manually, save it, then re-run my code and have it pick up on that width change.
Any ideas on what I can do to accomplish this?
First approach
Set wrap text cell style for whole description column (column B) in your template using Excel's GUI. Then do using following getPreferredCellStyle method to get that column cell style and set it as the preferred cell style for each cell in description column (column B).
CellStyle getPreferredCellStyle(Cell cell) {
// a method to get the preferred cell style for a cell
// this is either the already applied cell style
// or if that not present, then the row style (default cell style for this row)
// or if that not present, then the column style (default cell style for this column)
CellStyle cellStyle = cell.getCellStyle();
// if no explicit cell style applied then cellStyle.getIndex() is 0 for XSSF
// or 15 (0xF = the index to the default ExtendedFormatRecord (0xF)) for HSSF
if ((cell instanceof XSSFCell && cellStyle.getIndex() == 0) || (cell instanceof HSSFCell && cellStyle.getIndex() == 15)) cellStyle = cell.getRow().getRowStyle();
if (cellStyle == null) cellStyle = cell.getSheet().getColumnStyle(cell.getColumnIndex());
if (cellStyle == null) cellStyle = cell.getCellStyle();
return cellStyle;
}
Then
...
Cell description = nextRow.createCell(1);
description.setCellValue(fizz.getDescription());
description.setCellStyle(getPreferredCellStyle(description));
...
Second approach
Do using CellUtil to set wrap text cell style for each cell in description column.
...
Cell description = nextRow.createCell(1);
description.setCellValue(fizz.getDescription());
CellUtil.setCellStyleProperty(description, CellUtil.WRAP_TEXT, true);
...
For both approaches
Do not set autoSizeColumn for the description column (column B). In your example, only autosize column 0 (A) but not column 1 (B):
...
sheet.autoSizeColumn(0);
...
So the column width of column B remains unchanged as width as it is in the template.
I'm creating a .xlsx template using apache-poi, the user have to insert an id that has fixed length.
i've already tried the setDataFormat(workbook.createDataFormat().getFormat("#")) trick, but when the cell is edited it seems to forget that, and leading zeros disappear.
//this is the code snippet i found here on stackoverflow and tried out
DataFormat fmt = workbook.createDataFormat();
CellStyle textStyle = workbook.createCellStyle();
textStyle.setDataFormat(fmt.getFormat("#"));
worksheet.setDefaultColumnStyle(0, textStyle);
It would be great finding a true solution, because adding leading zeros to get the expected length can cause errors. Ex: user means 0000111 but forgets a 1 , new id will be 0000011 and unfortunately ids aren't sequential.
Thanks for your time, and forgive me for my bad english XD
Cannot reproduce your issue.
Following code creates a Excel sheet having Ids in column A which are not losing their text format and leading zeros even if edited in Excels GUI.
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
class CreateExcelNumberFormatText {
public static void main(String[] args) throws Exception {
try (Workbook workbook = new XSSFWorkbook();
FileOutputStream fileout = new FileOutputStream("Excel.xlsx") ) {
DataFormat format = workbook.createDataFormat();
CellStyle textStyle = workbook.createCellStyle();
textStyle.setDataFormat(format.getFormat("#"));
Sheet sheet = workbook.createSheet();
sheet.setDefaultColumnStyle(0, textStyle);
Cell cell = sheet.createRow(0).createCell(0);
cell.setCellStyle(textStyle);
cell.setCellValue("Id");
cell = sheet.createRow(1).createCell(0);
cell.setCellStyle(textStyle);
cell.setCellValue("0000111");
cell = sheet.createRow(2).createCell(0);
cell.setCellStyle(textStyle);
cell.setCellValue("0001111");
workbook.write(fileout);
}
}
}
What you probably not expected is that apache poi does not applying the column style to new created cells in that column. This you needs doing in code else the cell style will be General. Setting the column style is nevertheless necessary since else Excels GUI will not use the text style while adding cell contents there.
My code is complete, tested and works for me. Simply editing the cells in Excel cannot lead to lost of parts of cell contents (the leading zeros) because of using the number format # = Text.
Of course, if someone changes the column number format from Text to General, then 0000111 will be the number 111 after editing. But this is cannot be prevented when the sheet is editable by the user.
Maybe one could set CellStyle.setQuotePrefixed additionally. As:
...
textStyle.setDataFormat(format.getFormat("#"));
textStyle.setQuotePrefixed(true);
...
Then all content will be prefixed with a quote prefix apostrophe ' additionally. But this too can be changed by a user editing the sheet.
This was the solution for me :
cell = row.createCell(col, CellType.STRING);
cell.setCellValue(val);
I need some help to pass multi line text that I stored in ArrayLists into Excel cells. I made a parser to get values from each tag and now i'm trying to build my excel but I faced a problem that text from tags like this
<ProgramName>Mirror \n 2017</ProgramName>
looks like this Mirror \\n 2017if I manually copy it into setCellValue and I thinks this double slash is my problem but I have no idea why it's even here. and my code can't make it into a new line
//progName style
CellStyle cs = wb.createCellStyle();
cs.setWrapText(true);
cs.setVerticalAlignment(VerticalAlignment.CENTER);
cs.setAlignment(HorizontalAlignment.CENTER);
//progName text
Row row = sheet1.createRow((short) 1);
Cell cell = row.createCell((short) 1);
row.setHeightInPoints((2*sheet1.getDefaultRowHeightInPoints()));
String asd = String.valueOf(ProgramName.get(0));
cell.setCellValue(asd);
sheet1.addMergedRegion(new CellRangeAddress(1,1,1,8));
thanks to Andreas
String asd = String.valueOf(ProgramName.get(0)).replaceAll("\\\\n", "\n");
I am reading data from Excel using Apache POI. I want to convert some cells to number while reading in Java as following:
Input 01.0234500
Output 1.02345
Input 412206362371
Output 4.12206E+11
Input 1234.201400002345
Output 1234.2014
When I am using "Convert to Number" in Excel, it works fine. But I want the same output while reading Excel cells in Java.
It can also be achieved using =VALUE() function in Excel. But how do I implement the same functionality in Java?
I think there are a number of ways to accomplish what you stipulate, but the most direct method is just to use the VALUE() function and then evaluate it. This certainly is not the most efficient method, but it works.
Essentially we just read in the value of the input cell, then create a new cell formula cell which contains the VALUE() function with the original value as the parameter. After that we call evalutateInCell to evaluate the VALUE() function and replace the cell value with the results.
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet sheet = wb.createSheet("test");
Row row = sheet.createRow(0);
Cell inCell = row.createCell(0);
inCell.setCellValue("01.0234500");
Cell outCell = row.createCell(1);
FormulaEvaluator fev = wb.getCreationHelper().createFormulaEvaluator();
String value = inCell.getStringCellValue();
outCell.setCellFormula("VALUE(" + value + ")");
fev.evaluateInCell(outCell);
You can use the same method to replace the contents of the original cell if that is your preference.
This worked for me
new BigDecimal(cell.getNumericCellValue()).toPlainString()
I'm developing an Android App for filling a excel pre-formatted spreadsheet, using jxl. My issue is when i'm using the code for modifying cells according to the tutorial:
WritableCell cell = sheet0.getWritableCell(0,8);
if (cell.getType() == CellType.LABEL)
{
Label l = (Label) cell;
l.setString("hi");
}
It doesn't appear anything on the spreadsheet. Even the the cell if the document is formatted for text, still doesn't work. I've attempted to write a number using:
WritableCell cell = sheet0.getWritableCell(0,8);
if (cell.getType() == CellType.NUMBER)
{
Number l = (Number) cell;
l.setValue(1);
}
and format the cell on the document as a number type, and still doesn't work. The only way that i can write on the document is by using the addCell method:
Label label2 = new Label(0, 8, "X");
sheet0.addCell(label2);
But in this way, the system will just add a new cell, not modifying the content, and losing the original format (the most critical for me is the borders style).
Please advise.
Kind Regards.
I had exactly the same problem, and I ended up solving it like this:
Cell existingCell = worksheet.getCell(columnIndex, rowIndex);
Label label = new Label(columnIndex, rowIndex, "some string");
label.setCellFormat(existingCell.getCellFormat());
worksheet.addCell(label);