How to update cell reference values using Apache POI - java

I am using Apache POI to create new XSSFWorkbook from an existing one, after updating some values. Suppose I have two worksheets (Lets say: worksheet A & B) in my existing workbook. Worksheet B has some cell reference from Worksheet A. IF i modify those cell values of worksheet A and save them as a new workbook, corresponding cell values of worksheet B should be updated too. But it doesn't. How can i update them programmatically? . Thank you.
My code:
public void createExcel(ClientData cd) throws FileNotFoundException, IOException, InvalidFormatException{
// create a new file
double[] dataHolder1= cd.getFinalData1(), param1 = cd.getRecord1Param();
double[] dataHolder2 = cd.getFinalData2(), param2 = cd.getRecord2Param();
double[] ncv = cd.getNcv();
String[] pname = cd.getName();
Workbook workbook = new XSSFWorkbook(OPCPackage.open(new FileInputStream("template/mncv.xlsx"))); // or sample.xls
//CreationHelper createHelper = workbook.getCreationHelper();
Sheet s=workbook.getSheetAt(0);
int counter = dataHolder1.length + param1.length +param2.length+dataHolder2.length;//+ param1.length + param2.length;
// r = s.getRow(0);
// r.getCell(0).setCellValue("Param1");
// r.getCell(1).setCellValue("Record1");
// r.getCell(2).setCellValue("Param2");
// r.getCell(3).setCellValue("Record2");
int i;
for(i=0;i<counter;i++){
if(i<param1.length){
for(int j=0;j<param1.length;j++){
r = s.getRow(i);
r.getCell(0).setCellValue(param1[j]);
i++;
}
}else if(i<dataHolder1.length+param1.length && i>=param1.length){
for(int j=0;j<dataHolder1.length;j++){
r = s.getRow(i);
r.getCell(0).setCellValue(dataHolder1[j]);
i++;
}
}else if(i<dataHolder1.length+param1.length+param2.length && i>=dataHolder1.length+param1.length){
for(int j=0;j<param2.length;j++){
r = s.getRow(i);
r.getCell(0).setCellValue(param2[j]);
i++;
}
}else{
for(int j=0;j<dataHolder2.length;j++){
r = s.getRow(i);
r.getCell(0).setCellValue(dataHolder2[j]);
i++;
}
}
// if(i<=param1.length){
// r.getCell(0).setCellValue(param1[i-1]);
// r.getCell(2).setCellValue(param2[i-1]);
//
// }
// r.getCell(0).setCellValue(param1[i]);
//r.getCell(3).setCellValue(dataHolder2[i-1]);
i--;
}
for(int k=0;k<ncv.length;k++){
r = s.getRow(i);
r.getCell(0).setCellValue(ncv[k]);
i++;
}
s = workbook.getSheetAt(1);
s.getRow(2).getCell(5).setCellValue(pname[0]+" "+pname[1]+" "+pname[2]);
s.getRow(3).getCell(5).setCellValue(cd.getAge());
s.getRow(4).getCell(5).setCellValue(cd.getGender());
try (FileOutputStream out = new FileOutputStream("workbook.xlsx")) {
//WorkbookEvaluator we = new WorkbookEvaluator(workbook);
workbook.write(out);
out.close();
XSSFFormulaEvaluator.evaluateAllFormulaCells((XSSFWorkbook) workbook);
}catch(Exception e){
System.out.println(e);
}

The Excel file format caches the result of formula evaluation, to make opening the file quicker. This means that when you're done making changes to your file, you'll need to evaluate all of the formula cells to updated their cached value. (Otherwise, when you load the file in Excel, for almost all cases it'll still show the old value until you go into that cell)
Luckily, Apache POI provides code to do that, see the Formula Evaluation documentation for details. (You can choose to only recalculate certain formulas, if you know just those cells have changed, or do everything)

For any cell, say "B5", at runtime,
cell.getReference();
will give you cell reference (like in example... it will return you "B5")
cell.getReference().toString().charAt(0);
will give you the Column Reference (will give you "B" if the current cell is B5). Now
cell.getRowIndex();
OR
cell.getReference().toString().charAt(1);
will give you Row Index. Now you have the reference of the target cell. just replace these character with the references you have already created. This will update the cell references.

The following solution worked for me
wb.setForceFormulaRecalculation(true);
// replace "wb" with your HSSFWorkbook/XSSFWorkbook object

Related

Using Apache POI to write in xlsx file, Getting expected answer in the last column of the file

I am learning how to write in the xlsx file using Apache poi,Now in the below code i am using 2 array.
1.Month 2.Logging_Hours.
I am using Month array to assign the column name in the first row and it work fine for me.Now what i want the another Array in my code Logging_Hours print in each column but i am not getting the expected answer by using the below code.
For_Expected refer to the screen :"Expected_Xlsx"
For_Actual refer to the screen :"Actual_Xlsx"
public class Writing_xlsx {
public static void main(String[] args) throws IOException {
Workbook wb = new XSSFWorkbook();
Sheet sheet1=wb.createSheet("SheetOne");
String [] Month={"January" , "Feb", "March","Apr"};
int [] Logging_Hours={ 7 ,5, 9,10};
int f=0;
System.out.println(Month[0]);
Row r=sheet1.createRow(f);
for(int i=0;i<4;i++){
r.createCell(i).setCellValue(Month[i]);
}
for(int c=0;c<4;c++){}
int d=0;
while(d<4){
for(int rn=1;rn<=4;rn++) {
r=sheet1.createRow(rn);
r.createCell(d).setCellValue(Logging_Hours[rn-1]);
System.out.println(Logging_Hours[rn-1]);
}
d++;
}
FileOutputStream fileOut = new FileOutputStream("workbook.xlsx");
wb.write(fileOut);
fileOut.close();
wb.close();
}
}
For_Expected refer to the screen :"Expected_Xlsx"
For_Actual refer to the screen :"Actual_Xlsx"
Thank You in advance ,Sorry for the bad code i am just in a learning phase.
You will need two for loops (nested) to write the data, e.g.:
for (int rn = 1; rn <= 4; rn++) {
Row row = sheet1.createRow(rn);
for (int i = 0; i < 4; i++) {
row.createCell(i).setCellValue(Month[rn-1]);
}
}
Current for loop creates only one cell per row and writes the value into it whereas we need to write the values in all 4 cells per row.

What is causing excel to crash after updating file thru java?

I have some java code that opens an excel sheet, adds auto filter to a group of columns, then saves and closes. The problem is that when a user opens the file and trys to sort smallest to largest or largest to smallest excel will freeze then crash. But if you first filter then you can sort with out issue and it does not freeze and crash.
private static void AddFilter()
{
//Adds filter to the rows in Column 2
try
{
FileInputStream fileIn = new FileInputStream("C:\\Users\\gria\\Desktop\\Fleet Manager Summary.xls");
HSSFWorkbook report = new HSSFWorkbook(fileIn);
Sheet sheet = report.getSheetAt(0);
sheet.setAutoFilter(CellRangeAddress.valueOf("A5:P5"));
FileOutputStream fileOut = new FileOutputStream("C:\\Users\\gria\\Desktop\\Fleet Manager SummaryT.xls");
report.write(fileOut);
fileOut.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
Thank you,
UPDATE:
After some experimenting I have updated the info and code since the original question was asked to better explain the problem.
Try changing
XSSFFormulaEvaluator.evaluateAllFormulaCells(report);
to
HSSFFormulaEvaluator.evaluateAllFormulaCells(report);
XSSFFormulaEvaluator.evaluateAllFormulaCells() works for XSSfWorkbook, but not for the HSSFWorkbook.
Documentation
Also,
you can edit your commented code to:
for(int i = 5; i < sheet.getLastRowNum(); i++)
{
Cell cell = sheet.getRow(i).getCell(6);
//I don't know if you have data in all of the cells,
//So I suggest you to evaluate null
if(cell != null && !cell.getStringCellValue().isEmpty())
{
cell.setCellValue(Double.valueOf(cell.getStringCellValue()).doubleValue());
}
}

csv to xsl java , there is a column with some currency ( like $400 )

I want to convert csv to xsl using Java. Everything is working fine, but there is a column with some currency ( like $400 ) in the CSV file.
When these currency values are written to the XLS file, it shows green flags and we have to click and change its data type in Excel from string to number to get rid of the green flags.
Now to do so what is thought is to check that in a Cell if starting char is '$' then i will setCelltype to number but what to implement it in code ?
Please help new to excel and java too :P
//all imports are proper
public class Convert_CSV_XLS {
public static void main(String[] args) throws Exception{
/* Step -1 : Read input CSV file in Java */
String inputCSVFile = "csv_2_xls.csv";
CSVReader reader = new CSVReader(new FileReader(inputCSVFile));
/* Variables to loop through the CSV File */
String [] nextLine; /* for every line in the file */
int lnNum = 0; /* line number */
/* Step -2 : Define POI Spreadsheet objects */
HSSFWorkbook new_workbook = new HSSFWorkbook(); //create a blank workbook object
HSSFSheet sheet = new_workbook.createSheet("CSV2XLS"); //create a worksheet with caption score_details
/* Step -3: Define logical Map to consume CSV file data into excel */
Map<String, Object[]> excel_data = new HashMap<String, Object[]>(); //create a map and define data
/* Step -4: Populate data into logical Map */
while ((nextLine = reader.readNext()) != null) {
lnNum++;
excel_data.put(Integer.toString(lnNum), new Object[] {nextLine[0],nextLine[1]});
}
/* Step -5: Create Excel Data from the map using POI */
Set<String> keyset = excel_data.keySet();
int rownum = 0;
for (String key : keyset) { //loop through the data and add them to the cell
Row row = sheet.createRow(rownum++);
Object [] objArr = excel_data.get(key);
int cellnum = 0;
for (Object obj : objArr) {
Cell cell = row.createCell(cellnum++);
// Now here i want to check if first char of the value in cell is '$' or not.
if(obj instanceof Double)
cell.setCellValue((Double)obj);
else
cell.setCellValue((String)obj);
}
}
/* Write XLS converted CSV file to the output file */
FileOutputStream output_file = new FileOutputStream(new File("CSV2XLS.xls")); //create XLS file
new_workbook.write(output_file);//write converted XLS file to output stream
output_file.close(); //close the file
}
}
You should be able to check to see if a String starts with $ or not pretty easily. For setting cell types, it should look like this if you want Numeric:
cell.setCellType(HSSFCell.CELL_TYPE_NUMERIC);
Solved.
Used DataFormatter - https://poi.apache.org/apidocs/org/apache/poi/ss/usermodel/DataFormatter.html
cells cell.setCellValue(Double.parseDouble(str));
CellStyle cellStyle = wb.createCellStyle();
cellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("£#,‌​##0;[Red]-£#,##0"));
cell.setCellStyle(cellStyle);

read an external worksheet using apache poi in java

I am trying to create an excel which has the names. I need to execute a formula which needs to reference an external worksheet.
String formula = "=VLOOKUP(A2,[asd.xlsx]Sheet1!B$2:L$2045,11,0)";
System.out.println("formula: "+formula);
cell1.setCellFormula(formula);
When I execute this, I get the following exception.
java.lang.RuntimeException: not implemented yet
at org.apache.poi.xssf.usermodel.XSSFEvaluationWorkbook.getExternalSheetIndex(XSSFEvaluationWorkbook.java:127)
at org.apache.poi.ss.formula.FormulaParser.createAreaRefParseNode(FormulaParser.java:615)
I tried to use INDIRECT function, set that formula as text and execute the INDIRECT, but it did not work. Am I missing something?
Thanks.
Update 1:
Thanks for the comments. I did not use XSSFEEvaluationWorkbook. My code is below
FileInputStream abc = new FileInputStream(new File("Z_abc.xlsx"));
XSSFWorkbook workbookabc = new XSSFWorkbook(abc);
XSSFSheet sheetabc = workbookabc.getSheetAt(0);
Iterator<Row> rowIteratorRead = sheetabc.iterator();
while (rowIteratorRead.hasNext())
{
Row rowRead = rowIteratorRead.next();
if(rowRead.getRowNum()==0){
continue;
}//if(row.getRowNum()==0){
Cell cell = rowRead.getCell(0);
Cell cell1 = rowRead.getCell(1); //////////////////////////
if(cell1 == null) {
cell1 =rowRead.createCell(1);
int rowNumber = (rowRead.getRowNum()+1);
String formula = "VLOOKUP(A2,[asd.xlsx]Sheet1!B$2:L$2045,11,0)";
//System.out.println("formula: "+formula);
cell1.setCellFormula(formula);
//cell1.setCellValue(formula);
}//if(cell1 == null) {
}//while (rowIteratorRead.hasNext())
I was successful in getting the formulas work if they refer from same workbook without using XSSFEEvaluationWorkbook.
Thanks.

Excel cannot understand the format of data written by java

I am having 2 issues using the apache POI to write data from a csv into an excel file.
The data consists of dates, and numbers
The issues are:
1) The numbers are written as strings.
2) Excel cannot read the date format (this messes the graphs up)
The code (that I received help with previously):
String name = "test";
Sheet sheet = wb.getSheet(name);
if (sheet == null) {
sheet = wb.createSheet(name);
}
int rowCount = 0;
Scanner scanner = new Scanner(new File("/tmp/" + name + ".csv"));
while (scanner.hasNextLine()) {
String[] rowData = scanner.nextLine().split(",");
for (int col = 0; col < rowData.length; col++) {
Row row = sheet.getRow(rowCount);
if (row == null)
row = sheet.createRow(rowCount);
Cell cell = row.getCell(col);
if (cell == null) {
cell = row.createCell(col);
}
cell.setCellValue(rowData[col]);
}
rowCount++;
}
wb.write(new FileOutputStream(excel));
}
1) I tried using Double.parseDouble(rowData[col]) when entering the data into the excel file. but this gives an empty string error. I even set the cell format with style.setDataFormat(format.getFormat("#,##0.0000")); but it still does not work
2) I tried using the date format cellStyle.setDataFormat(createHelper.createDataFormat().getFormat("m/d/yyyy hh:mm:ss")); but still the excel graphs can't read this format. (when I manually copy and paste from the csv file it works).
So basically, when copying data using the apache poi, none of the other data that relies on the copied cells is updated.
for example if a cell has a value of the average of 100 cells, and I manually copy data into those cells, it updates automatically. But when it copies through java, the cells do not update.
The following should do something more.
try {
double value = Double.parseDouble(rowData[col]);
cell.setCellValue(value);
} catch (NumberFormatException | NullPointerException e) {
String value = rowData[col];
cell.setCellValue(value);
}
(However you might not use Apache POI and straight copy the CSV file to a .xls, if
it is just a need for double-click reading by Excel.)

Categories