All:
I am pretty new to Apache POI, I wonder if I want to use the builtin function from excel VBA, how can I do that?
For example:
In VBA, I can write something like:
Dim month as String
month = MonthName( Month( Sheets1.Range("C12") ) )
How can I use that function in Apache POI(I do not wanna give that formula to a cell and evaluate it)?
Thanks,
POI does not provide a VBA engine, so you cannot execute VBA with POI.
But there's a way to implement equivalent code in Java and use it with POI. The link below gives an example of how to do that.
https://poi.apache.org/spreadsheet/user-defined-functions.html
Apache poi cannot interpret VBA but of course it has a formula evaluator. So of course you can evaluate Excel formulas directly in apache poi code.
But the VBA function MonthName is not implemented by default. So either you do getting the date from the cell, what is clearly possible using apache poi. And then, you get the month and the month name out of that date using Java code. This is called first approach in following example.
Or you are using a implemented Excel function. TEXT for example. This is called second approach in following example.
import java.io.FileInputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.formula.WorkbookEvaluator;
import org.apache.poi.ss.formula.eval.*;
public class ExcelEvaluateMonthFunctions{
public static void main(String[] args) throws Exception {
Workbook workbook = WorkbookFactory.create(new FileInputStream("workbook.xlsx"));
Sheet sheet = workbook.getSheet("Sheet2");
java.util.Locale.setDefault(java.util.Locale.US);
//first approach:
String monthname = null;
java.util.Date date = sheet.getRow(11).getCell(2).getDateCellValue(); //Sheet2!C12 must contain a date
java.time.LocalDate localDate = date.toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDate();
monthname = localDate.getMonth().getDisplayName(java.time.format.TextStyle.FULL, java.util.Locale.getDefault());
System.out.println(monthname);
//second approach:
monthname = null;
CreationHelper helper = workbook.getCreationHelper();
XSSFFormulaEvaluator formulaevaluator = (XSSFFormulaEvaluator)helper.createFormulaEvaluator();
WorkbookEvaluator workbookevaluator = formulaevaluator._getWorkbookEvaluator();
ValueEval valueeval = null;
valueeval = workbookevaluator.evaluate("TEXT(" + sheet.getSheetName() +"!C12, \"MMMM\")", null); //Sheet2!C12 must contain a date
if (valueeval instanceof StringValueEval) {
monthname = ((StringValueEval)valueeval).getStringValue();
}
System.out.println(monthname);
workbook.close();
}
}
Related
I've got an Excel file I want to recreate through POI. The existing Excel file uses as DataFormat _(* #.##0_);_(* (#.##0);_(* "-"??_);_(#_). But when I assign that data format through POI, the resulting Excel file will instead use _(* #,##0_);_(* (#,##0);_(* "-"??_);_(#_). Note the tiny difference: a dot changed to a comma. Because of this, the entire format doesn't work anymore. It's not like it's now showing a comma where it used to have a dot; it's formatting the entire value in a completely different way.
Why does this happen? And how do I fix it?
The correct format string _(* #.##0_);_(* (#.##0);_(* "-"??_);_(#_) results in the number being displayed as 13.534.000.
The incorrect format string that Excel or POI changes it to, _(* #,##0_);_(* (#,##0);_(* "-"??_);_(#_) formats the value as 13534000,0.
It's a complete mystery to me why it would do that. I suppose it has something to do with the US and Europe using different formats to display big numbers, but I would imagine that that's exactly what this data format is supposed to address. Instead, it turns it into nonsense.
Apache POI creates Microsoft Office files. Those files never are localized. They always store data in en_US locale. The locale dependent adjustments are done in locale Office applications then. So a Microsoft Office file can be sent around the world without the need to change the stored data to a foreign locale.
So if you set the data format using ...
...
Workbook workbook = new XSSFWorkbook();
DataFormat dataformat = workbook.createDataFormat();
CellStyle cellStyle = workbook.createCellStyle();
cellStyle.setDataFormat(dataformat.getFormat("_(* #,##0_);_(* (#,##0);_(* \"-\"??_);_(#_)"));
...
... the format pattern always needs to be en_US. That means dot is decimal separator, comma is thousands delimiter. A locale Excel application might adjust that to _(* #.##0_);_(* (#.##0);_(* "-"??_);_(#_) then.
Let's have a complete example:
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class CreateExcelNumberFormat {
public static void main(String[] args) throws Exception {
Workbook workbook = new XSSFWorkbook();
DataFormat dataformat = workbook.createDataFormat();
CellStyle cellStyle = workbook.createCellStyle();
cellStyle.setDataFormat(dataformat.getFormat("_(* #,##0_);_(* (#,##0);_(* \"-\"??_);_(#_)"));
Sheet sheet = workbook.createSheet();
Row row = sheet.createRow(0);
Cell cell = row.createCell(0);
cell.setCellValue(1234567.89);
cell.setCellStyle(cellStyle);
row = sheet.createRow(1);
cell = row.createCell(0);
cell.setCellValue(-1234567.89);
cell.setCellStyle(cellStyle);
sheet.setColumnWidth(0, 15*256);
FileOutputStream out = new FileOutputStream("./CreateExcelNumberFormat.xlsx");
workbook.write(out);
out.close();
workbook.close();
}
}
The result Excel file looks in my German Excel like so:
When use setCellFormula set by paramete "CHISQ.TEST(ChiSq_Data!D5:F5,ChiSq_Data!L5:N5)",but the output was "=#CHISQ.TEST(ChiSq_Data!D5:F5,ChiSq_Data!L5:N5)", the # symbol make the formula did not work and shows #VALUE in the result excel.
How can I remove the # automatically?
This is a similar problem as this one: Apache POI Excel Formula entering # Symbols where they don't belong.
All new functions (introduced after Excel 2007) are prefixed with _xlfn in internally file storage. The GUI does not show that prefix if the Excel version is able to interpret that function. If the Excel version is too old to be able to interpret that function you may see that prefix even in GUI.
Apache POI creates Excel files and that's why writes formulas in file storage directly. Using:
cell.setCellFormula("CHISQ.TEST(ChiSq_Data!D5:F5,ChiSq_Data!L5:N5)");
it writes CHISQ.TEST(ChiSq_Data!D5:F5,ChiSq_Data!L5:N5) into the file storage but the Excel GUI expects _xlfn.CHISQ.TEST(ChiSq_Data!D5:F5,ChiSq_Data!L5:N5). That's why the #NAME? error.
But why the #? The # is the implicit intersection operator. Implicit intersection is a new feature of Excel 365 (a silly one in my opinion, as well as dynamic array and spilling array behavior). And because Excel 365 does not know the function CHISQ.TEST without the prefix but it contains arrays of cells as parameters, it puts # in front of it to show that it would use implicit intersection if it would know it.
So the solution is to put the correct prefix before the function name in file storage to make it work:
cell.setCellFormula("_xlfn.CHISQ.TEST(ChiSq_Data!D5:F5,ChiSq_Data!L5:N5)");
Complete example to test:
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCell;
class CreateExcelCHISQ_TEST {
public static void main(String[] args) throws Exception {
try (
Workbook workbook = new XSSFWorkbook(); FileOutputStream fileout = new FileOutputStream("Excel.xlsx") ) {
Sheet sheet = workbook.createSheet();
Row row;
Cell cell;
// Filling dummy data to another sheet
Sheet otherSheet = workbook.createSheet("ChiSq_Data");
row = otherSheet.createRow(4);
row.createCell(3).setCellValue(123);
row.createCell(4).setCellValue(456);
row.createCell(5).setCellValue(78);
row.createCell(11).setCellValue(122.5);
row.createCell(12).setCellValue(456.5);
row.createCell(13).setCellValue(77.5);
row = sheet.createRow(0);
cell = row.createCell(0);
//cell.setCellFormula("CHISQ.TEST(ChiSq_Data!D5:F5,ChiSq_Data!L5:N5)"); // wrong
cell.setCellFormula("_xlfn.CHISQ.TEST(ChiSq_Data!D5:F5,ChiSq_Data!L5:N5)");
workbook.write(fileout);
}
}
}
Selenium is incorrectly reading the date as 43095 when I enter 26-12-2017. How to get Selenium to read the correct date?
for (int i=0;i<=TcRow;i++)
{
for (int j=0;j<TcCol;j++)
{
Cell Cell=TcSheet.getRow(i).getCell(j);
}
}
Am I reading the format incorrectly?
TcSheet.getRow(i).getCell(j).setCellType(Cell.CELL_TYPE_STRING);
What changes do I need to do here to make sure they read both the string and the date field?
data[i][j]=TcSheet.getRow(i).getCell(j).getStringCellValue();
}
I also faced the same issue during reading the excel file where I'm fetching date is formatted in dd/mm/yyyy format and selenium fetching wrong value.
For that, I have used DataFormatter. It will returns Excel cell value with format e.g. Date format 15-04-208 in excellent then it will returns date with same format. Look below code that I used in my Framework. Hope it will also work for you.
FileInputStream fis = new FileInputStream("path\\to\\file.xlsx");
XSSFWorkbook workbook = new XSSFWorkbook(fis);
XSSFSheet sheet = workbook.getSheetAt(worksheet);
DataFormatter formatter = new DataFormatter();
Cell cell = sheet.getRow(rowNum).getCell(cellNum);
String cellValue = formatter.formatCellValue(cell);
System.out.println(cellValue);
return cellValue;
Let me know if you have any query.
I'm having trouble with Excel's custom format using EPPLUS. Here's my code:
var destFile = new FileInfo(#"C:\temp\test1.xlsx");
var fileName = "test1";
using (ExcelPackage pck = new ExcelPackage(destFile))
{
pck.Workbook.Worksheets.Add(fileName); // Create the worksheet in package
pck.Workbook.Worksheets[fileName].Cells["A2"].Value = DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss");
pck.Workbook.Worksheets[fileName].Cells["A2"].Style.Numberformat.Format = "d-mmm-yy";
pck.Save();
}
I'm getting the following:
The custom format is showed right, but the value in the cell doesn't display the format needed. Here's what I'm trying to get:
Note: I need the full date value DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss") for other files, but the custom format is all I need for this file.
What do I need to change to get this to work?
Thanks to #PaullAbbott, here's the correct answer:
pck.Workbook.Worksheets[fileName].Cells["A2"].Value = DateTime.Now;
This displays the results that I needed.
I would like to create a progress bar within a Excel-sheet cell. I must use Apache Poi library, but I do not know how to even start. (Something like this, but using the Java library) http://www.tech-recipes.com/rx/35064/excel-2013-create-progress-bars/
I guess I must put a conditional formating, but I do know how it works and I can not find a solution anywhere ... somebody can help me out?
Thanks in advance.
As you suggested, I've used your link to create an example xlsx and simply recreated the necessary xml structures, i.e. open the xlsx file as zip archive and have a look at xl/worksheets/sheet1.xml. Beside the poi-ooxml.jar you'll need the ooxml-schemas-1.1.jar.
(tested with Libre Office 4.0, Excel Viewer 2010, POI 3.10-beta1)
import java.io.FileOutputStream;
import java.lang.reflect.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
public class Databar {
public static void main(String[] args) throws Exception {
Workbook wb = new XSSFWorkbook();
Sheet sheet = wb.createSheet();
for (int i=0; i<4; i++) {
sheet.createRow(i).createCell(0).setCellValue(new int[]{12,38,93,42}[i]);
}
SheetConditionalFormatting cf = sheet.getSheetConditionalFormatting();
XSSFConditionalFormattingRule xcfrule =
(XSSFConditionalFormattingRule)cf.createConditionalFormattingRule("");
Method m = XSSFConditionalFormattingRule.class.getDeclaredMethod("getCTCfRule");
m.setAccessible(true);
CTCfRule cfRule = (CTCfRule)m.invoke(xcfrule);
cfRule.removeFormula(0); // cleanup
cfRule.setType(STCfType.DATA_BAR);
CTDataBar databar = cfRule.addNewDataBar();
CTCfvo vfoMin = databar.addNewCfvo();
vfoMin.setType(STCfvoType.NUM);
vfoMin.setVal("0");
CTCfvo vfoMax = databar.addNewCfvo();
vfoMax.setType(STCfvoType.NUM);
vfoMax.setVal("100");
CTColor color = databar.addNewColor();
color.setRgb(new byte[]{(byte)0xFF, 0x00, 0x00, (byte)0xFF});
CellRangeAddress cra[] = {new CellRangeAddress(0, 3, 0, 0)};
cf.addConditionalFormatting(cra, xcfrule);
FileOutputStream fos = new FileOutputStream("databar-out.xlsx");
wb.write(fos);
fos.close();
}
}