Apache POI xls column Remove - java

I don't find how to remove a column with the Apache POI API.
I would appreciate a sample code or help on this point.

Alan Williamson on the mailing list wrote a small helper for column removal
package org.alanwilliamson.openbd.plugin.spreadsheet;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
/*
* Helper functions to aid in the management of sheets
*/
public class SheetUtility extends Object {
/**
* Given a sheet, this method deletes a column from a sheet and moves
* all the columns to the right of it to the left one cell.
*
* Note, this method will not update any formula references.
*
* #param sheet
* #param column
*/
public static void deleteColumn( Sheet sheet, int columnToDelete ){
int maxColumn = 0;
for ( int r=0; r < sheet.getLastRowNum()+1; r++ ){
Row row = sheet.getRow( r );
// if no row exists here; then nothing to do; next!
if ( row == null )
continue;
// if the row doesn't have this many columns then we are good; next!
int lastColumn = row.getLastCellNum();
if ( lastColumn > maxColumn )
maxColumn = lastColumn;
if ( lastColumn < columnToDelete )
continue;
for ( int x=columnToDelete+1; x < lastColumn + 1; x++ ){
Cell oldCell = row.getCell(x-1);
if ( oldCell != null )
row.removeCell( oldCell );
Cell nextCell = row.getCell( x );
if ( nextCell != null ){
Cell newCell = row.createCell( x-1, nextCell.getCellType() );
cloneCell(newCell, nextCell);
}
}
}
// Adjust the column widths
for ( int c=0; c < maxColumn; c++ ){
sheet.setColumnWidth( c, sheet.getColumnWidth(c+1) );
}
}
/*
* Takes an existing Cell and merges all the styles and forumla
* into the new one
*/
private static void cloneCell( Cell cNew, Cell cOld ){
cNew.setCellComment( cOld.getCellComment() );
cNew.setCellStyle( cOld.getCellStyle() );
switch ( cNew.getCellType() ){
case Cell.CELL_TYPE_BOOLEAN:{
cNew.setCellValue( cOld.getBooleanCellValue() );
break;
}
case Cell.CELL_TYPE_NUMERIC:{
cNew.setCellValue( cOld.getNumericCellValue() );
break;
}
case Cell.CELL_TYPE_STRING:{
cNew.setCellValue( cOld.getStringCellValue() );
break;
}
case Cell.CELL_TYPE_ERROR:{
cNew.setCellValue( cOld.getErrorCellValue() );
break;
}
case Cell.CELL_TYPE_FORMULA:{
cNew.setCellFormula( cOld.getCellFormula() );
break;
}
}
}
}

The answer of cporte is perfectly fine but imho a bit hard to read.
The Idea:
For every row, delete the cell representing the column which shall be deleted and move all cells to the right of this column one to the left.
The simplified Implementation:
//Variables for completeness
Sheet sheet;
int columnToDelete;
for (int rId = 0; rId <= sheet.getLastRowNum(); rId++) {
Row row = sheet.getRow(rId);
for (int cID = columnToDelete; cID < row.getLastCellNum(); cID++) {
Cell cOld = row.getCell(cID);
if (cOld != null) {
row.removeCell(cOld);
}
Cell cNext = row.getCell(cID + 1);
if (cNext != null) {
Cell cNew = row.createCell(cID, cNext.getCellType());
cloneCell(cNew, cNext);
sheet.setColumnWidth(cID, sheet.getColumnWidth(cID + 1));
}
}
}
The clone cell method copied from the other answer for completeness:
private static void cloneCell( Cell cNew, Cell cOld ){
cNew.setCellComment( cOld.getCellComment() );
cNew.setCellStyle( cOld.getCellStyle() );
switch ( cNew.getCellType() ){
case Cell.CELL_TYPE_BOOLEAN:{
cNew.setCellValue( cOld.getBooleanCellValue() );
break;
}
case Cell.CELL_TYPE_NUMERIC:{
cNew.setCellValue( cOld.getNumericCellValue() );
break;
}
case Cell.CELL_TYPE_STRING:{
cNew.setCellValue( cOld.getStringCellValue() );
break;
}
case Cell.CELL_TYPE_ERROR:{
cNew.setCellValue( cOld.getErrorCellValue() );
break;
}
case Cell.CELL_TYPE_FORMULA:{
cNew.setCellFormula( cOld.getCellFormula() );
break;
}
}
}

codewing's solution worked for me like a charm with the following minor changes:
When we clone the cell, the call should be cloneCell(cNew, cNext)
We should set the column width only for the first row.
I'm using version 3.17 of the api, so a few things changed (like CellType changed from int to an enum).
Full code is below (for clarity):
private void deleteColumn(Sheet sheet, int columnToDelete) {
for (int rId = 0; rId < sheet.getLastRowNum(); rId++) {
Row row = sheet.getRow(rId);
for (int cID = columnToDelete; cID < row.getLastCellNum(); cID++) {
Cell cOld = row.getCell(cID);
if (cOld != null) {
row.removeCell(cOld);
}
Cell cNext = row.getCell(cID + 1);
if (cNext != null) {
Cell cNew = row.createCell(cID, cNext.getCellTypeEnum());
cloneCell(cNew, cNext);
//Set the column width only on the first row.
//Other wise the second row will overwrite the original column width set previously.
if(rId == 0) {
sheet.setColumnWidth(cID, sheet.getColumnWidth(cID + 1));
}
}
}
}
}
private void cloneCell(Cell cNew, Cell cOld) {
cNew.setCellComment(cOld.getCellComment());
cNew.setCellStyle(cOld.getCellStyle());
if (CellType.BOOLEAN == cNew.getCellTypeEnum()) {
cNew.setCellValue(cOld.getBooleanCellValue());
} else if (CellType.NUMERIC == cNew.getCellTypeEnum()) {
cNew.setCellValue(cOld.getNumericCellValue());
} else if (CellType.STRING == cNew.getCellTypeEnum()) {
cNew.setCellValue(cOld.getStringCellValue());
} else if (CellType.ERROR == cNew.getCellTypeEnum()) {
cNew.setCellValue(cOld.getErrorCellValue());
} else if (CellType.FORMULA == cNew.getCellTypeEnum()) {
cNew.setCellValue(cOld.getCellFormula());
}
}

I think you have to go down each HSSFRow and call HSSFRow.getCell and then HSSFRow.removeCell. The API is oriented towards rows, rather than columns, and very few operations work at the whole column level.
Sample code (untested):
HSSFSheet sheet = ...
int colToRemove = 5;
Iterator rowIter = sheet.iterator();
while (rowIter.hasNext()) {
HSSFRow row = (HSSFRow)rowIter.next();
HSSFCell cell = row.getCell(colToRemove);
row.removeCell(cell);
}

There is a term confusion: the action that author author would like to achieve is called column shift it terms of Apache POI interface. org.apache.poi.ss.usermodel.Sheet interface provide a clean method to do such thing:
sheet.shiftColumns(startRangeIndex, endRangeIndex, directionQuantifier);
For instance, moving Column B to one position left is easily achievable by calling:
Sheet sheet = loadRequiredSheet();
sheet.shiftColumns(2, 3, -1);
Column A Column B Column C
Data here to be removed <- t should be moved to the left

The code above is working perfectly but I did some modification over the POI version which we are using in case you are using POI version4.0.0.
You can refer the code below for deleting column in excel by using java and POI.
public static void deleteColumn(XSSFSheet sheet, int columnToDelete) {
for (int rId = 0; rId < sheet.getLastRowNum(); rId++) {
Row row = sheet.getRow(rId);
for (int cID = columnToDelete; cID < row.getLastCellNum(); cID++) {
Cell cOld = row.getCell(cID);
if (cOld != null) {
row.removeCell(cOld);
}
Cell cNext = row.getCell(cID + 1);
if (cNext != null) {
Cell cNew = row.createCell(cID, cNext.getCellType());
cloneCell(cNew, cNext);
//Set the column width only on the first row.
//Other wise the second row will overwrite the original column width set previously.
if(rId == 0) {
sheet.setColumnWidth(cID, sheet.getColumnWidth(cID + 1));
}
}
}
}
}
public static void cloneCell(Cell cNew, Cell cOld) {
cNew.setCellComment(cOld.getCellComment());
cNew.setCellStyle(cOld.getCellStyle());
if (CellType.BOOLEAN == cNew.getCellType()) {
cNew.setCellValue(cOld.getBooleanCellValue());
} else if (CellType.NUMERIC == cNew.getCellType()) {
cNew.setCellValue(cOld.getNumericCellValue());
} else if (CellType.STRING == cNew.getCellType()) {
cNew.setCellValue(cOld.getStringCellValue());
} else if (CellType.ERROR == cNew.getCellType()) {
cNew.setCellValue(cOld.getErrorCellValue());
} else if (CellType.FORMULA == cNew.getCellType()) {
cNew.setCellValue(cOld.getCellFormula());
}
}

Related

Java merge two cells into one in EXCEL

I am trying to merge two cells into one
for (String cellLLL : sheetNumd) {
XSSFSheet sheets = workbook.getSheet(cellLLL);
if (sheets != null) {
for (int rowNum = 4; rowNum < sheets.getLastRowNum() + 1; rowNum++) {
Row row = sheets.getRow(rowNum);
//sheets.addMergedRegion(new CellRangeAddress(4, 5, 6, 6));
if (row != null) {
for (Cell cell : row) {
int columnIndex = cell.getColumnIndex();
switch (columnIndex) {
case 6:
cellValue6 = cell.getStringCellValue();
break;
}
}
}
if (cellLLL.equals("Sheet1")) {
list6.add(cellValue6);
}
The cells I want to merge are G5 and G6
In my example I comment out the code where I am trying to do it. But if I run it, then I get an error -
java.lang.IllegalStateException: Cannot add merged region G5:G6 to sheet because it overlaps with an existing merged region (G5:G6).
Maybe I'm doing something wrong. Please tell me
The library I am using is Apache Poi

How to Clone Function with relative Reference on HSSF apache poi (JAVA)

I'm try to make a export Excel, and i need some formula for count number in my excel , but i have a data from database and it will be more than one. so i wanna clone that formula to next data.
it goes well , but the reference cell can't change to next cell, like if we tried copy cell from excel
cellOne[data].setCellFormula(celltwo[data].getCellFormula());
i want to copy count from data1 to data2
Instead of manipulating the formula strings to update formula references, best practice is really using a FormulaParser in my opinion. Advantage is that really all possible formulas can be updated as long as the FormulaParser knows them. Manipulating the formula strings easily leads to problems. For example a formula template like "SUM(H%d;I%d)" has %d as a variable to be replaced. But the percent sign could also be a not variable part in some formulas.
The apache poi has a FormulaParser which can be used. In Apache POI update formula references when copying I have shown this already for XSSF only.
Since this question is about HSSF I will show an String copyFormula(Sheet sheet, String formula, int coldiff, int rowdiff) method which works for SS that is for HSSFas well as for XSSF.
import java.io.FileOutputStream;
import org.apache.poi.ss.formula.*;
import org.apache.poi.ss.formula.ptg.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFEvaluationWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook;
public class ExcelCopyFormula {
private static String copyFormula(Sheet sheet, String formula, int coldiff, int rowdiff) {
Workbook workbook = sheet.getWorkbook();
EvaluationWorkbook evaluationWorkbook = null;
if (workbook instanceof HSSFWorkbook) {
evaluationWorkbook = HSSFEvaluationWorkbook.create((HSSFWorkbook) workbook);
} else if (workbook instanceof XSSFWorkbook) {
evaluationWorkbook = XSSFEvaluationWorkbook.create((XSSFWorkbook) workbook);
}
Ptg[] ptgs = FormulaParser.parse(formula, (FormulaParsingWorkbook)evaluationWorkbook,
FormulaType.CELL, sheet.getWorkbook().getSheetIndex(sheet));
for (int i = 0; i < ptgs.length; i++) {
if (ptgs[i] instanceof RefPtgBase) { // base class for cell references
RefPtgBase ref = (RefPtgBase) ptgs[i];
if (ref.isColRelative())
ref.setColumn(ref.getColumn() + coldiff);
if (ref.isRowRelative())
ref.setRow(ref.getRow() + rowdiff);
}
else if (ptgs[i] instanceof AreaPtgBase) { // base class for range references
AreaPtgBase ref = (AreaPtgBase) ptgs[i];
if (ref.isFirstColRelative())
ref.setFirstColumn(ref.getFirstColumn() + coldiff);
if (ref.isLastColRelative())
ref.setLastColumn(ref.getLastColumn() + coldiff);
if (ref.isFirstRowRelative())
ref.setFirstRow(ref.getFirstRow() + rowdiff);
if (ref.isLastRowRelative())
ref.setLastRow(ref.getLastRow() + rowdiff);
}
}
formula = FormulaRenderer.toFormulaString((FormulaRenderingWorkbook)evaluationWorkbook, ptgs);
return formula;
}
public static void main(String[] args) throws Exception {
//String type = "XSSF";
String type = "HSSF";
try (Workbook workbook = ("XSSF".equals(type))?new XSSFWorkbook():new HSSFWorkbook();
FileOutputStream out = new FileOutputStream(("XSSF".equals(type))?"Excel.xlsx":"Excel.xls") ) {
Sheet sheet = workbook.createSheet();
for (int r = 2 ; r < 10; r++) {
Row row = sheet.createRow(r);
for (int c = 2 ; c < 5; c++) {
Cell cell = row.createCell(c);
if (r == 2) {
if (c == 2) cell.setCellValue("No");
if (c == 3) cell.setCellValue("Number One");
if (c == 4) cell.setCellValue("Number Two");
} else {
if (c == 2) cell.setCellValue("data" + (r-2));
if (c == 3) cell.setCellValue(r*c);
if (c == 4) cell.setCellValue(r*c);
}
}
}
for (int r = 2 ; r < 10; r++) {
Row row = sheet.getRow(r);
Cell cell = row.createCell(5);
String formula = "D4+E4";
if (r == 2) cell.setCellValue("Formula");
else cell.setCellFormula(copyFormula(sheet, formula, 0, r-3));
}
for (int r = 2 ; r < 10; r++) {
Row row = sheet.getRow(r);
Cell cell = row.createCell(6);
String formula = "G4+F5";
if (r == 2) cell.setCellValue("Cumulative");
else if (r == 3) cell.setCellFormula("F4");
else cell.setCellFormula(copyFormula(sheet, formula, 0, r-4));
}
workbook.getCreationHelper().createFormulaEvaluator().evaluateAll();
workbook.write(out);
}
}
}

iterating over the columns of a row through poi in java

I have a excel file named abc.xls in my c: drive (local computer) , now in that excel file in the first sheet itself there is a table as shown below and this below table can lie in any range with in the sheet so i have developed the below java program which will scan the entire sheet first by row basis and then on column basis and will find the cell where
TradeRef is there
TradeRef TMS Deal Date
12 45 DRT 23/97/2014
23 36 QWE 21/07/2015
now the problem in my below program is that it captures the cell where TradeRef is there and then it iterates over the columns and then in similar fashion it captures the next row and iterating over the columns
but the logic that i want to apply is that when it captures the TradeRef cell and iterating over the columns and reached to the last column of the table which is Date in the above table then it should further scan the next 20 columns within the same row and if within the next 20 columns there is no cell having any value then it should move to the next row and if within the 20 columns it mite be that any cell can have value then in that case it should read that cell value
so it would be like
TradeRef TMS Deal Date <----- scan next 20 columns is there is no value in next 20 cells then move to next row else include that cell value also------->
12 45 DRT 23/97/2014
23 36 QWE 21/07/2015
so please advise how to implement the above logic of scanning the next 20 columns within the row below is my earlier implementation that is
public class AAA {
public static void main(String[] args) throws IOException {
FileInputStream file = null ;
try {
file = new FileInputStream(new File("C:\\abc.xls"));
HSSFWorkbook workbook = new HSSFWorkbook(file);
HSSFSheet firstSheet = workbook.getSheetAt(0);
Iterator<Row> iterator = firstSheet.iterator();
Cell c = findFirstRow(firstSheet);
}
catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
file.close();
}
}
public static Cell findFirstRow(HSSFSheet firstSheet) {
for (Row row : firstSheet) {
for (Cell cell : row) {
cell.setCellType(cell.CELL_TYPE_STRING);
if ("TradeRef".equals(cell.getStringCellValue())) {
int row1 = cell.getRowIndex() + 1;
int col = cell.getColumnIndex();
if (firstSheet.getRow(row1) == null)
throw new RuntimeException("Row " + row1 + 1 + " is empty!");
Cell startOfFirstDataRow = firstSheet.getRow(row1).getCell(col);
if (startOfFirstDataRow == null) {
CellReference ref = new CellReference(row1, col);
throw new RuntimeException("Data not found at " + ref.formatAsString());
}
return startOfFirstDataRow;
}
}
}
throw new RuntimeException("TradingRef header cell not found!");
}
}
so please advise how can i implement the above logic of scanning next 20 columns
First, you should probably use the org.apache.poi.ss.usermodel API, which work with all Excel files while the HSSF* classes only work with .xls files.
The org.apache.poi.ss.usermodel.Sheet class has a getFirstRow() method that you can use to start your search. Next you want to find a sequence of Cells containing the given Strings, like:
// This is an array containing the headers
final String[] headers = { "TradeRef", "TMS", "Deal", "Date" };
// now we take row from above to be the Row object where we seek our headers
int last = row.getLastCellNum();
for (int c = row.getFirstCellNum(); c < last; c++) {
int h = 0;
// check if the cell at (c + h) has the required value
for (; h < headers.length && c + h < last; h++) {
if (!headers[h].equals(row.getCell(c + h).getStringCellValue())) {
break; // if the cell value differs from our header
}
}
if (h == headers.length) // this means the break was never invoked
return c; // found it
}
return -1; // not found
if you want to skip column you can use
while (cellsInRow.hasNext()) {
Cell currentCell = cellsInRow.next();
if (currentCell.getColumnIndex() >= 3 && currentCell.getColumnIndex() <= 6) {
continue;
}
}
to skip column 4, 5, 6 and 7 from excel file. index starts at 0

Reading multiple excel sheet

I am trying to read the sheets of a spread sheet uisng a foor loop. I wanted to know is this the right way of reading especially the use of Sheet Propety [highlighted in the code] :
Cell[][] newcell=new Cell[200][200];
int newsheet = workbook1.getNumberOfSheets();
for (int q=1;q < newsheet;q++)
{
for(int p=0;p < sheet(q).getColumns();p++)
{
for(int p1=0;p1<sheet(q).getRows();p1++)
/*^^^^^^^^^*/
{
newcell[p][p1] = sheet(q).getCell(p, p1);
/*^^^^^^^^^*/
if(newcell[p][p1].equals(saved[j]))
{
System.out.print( newcell[p][0]);
}
}
}
}
Can I use the property of sheet() as sheet(q) because its throwing NullPointerException?
The usual style for working with all the cells in POI is:
for(int sheetNum=0; sheetNum < wb.getNumberOfSheets(); sheetNum++) {
Sheet sheet = wb.getSheetAt(sheetNum);
for (Row row : sheet) {
for (Cell cell : row) {
// Do something here
}
}
}
Maybe switch your code to something more like that?
With jxl (JExcelAPI), this should work:
for (Sheet sheet:workbook1.getSheets()) { // getSheet() returns a Sheet[]
int numCols = sheet.getColumns(); // getColumns() returns an int
for(for int i = 0; i <= numCols; i++) {
Cell[] column = sheet.getColumn(i);
for(Cell cell:column) { // column is a Cell[]
if(cell.equals(saved[j])) {
System.out.print(cell);
}
}
}
}

POI / Excel : applying formulas in a "relative" way

I'm using Apache's POI to manipulate Excel (.xls) files with Java.
I'm trying to create a new cell whom content is the result of a formula as if the user had copied/pasted the formula (what i call the "relative" way, as opposite to "absolute").
To make myself clearer, here is a simple example:
Cell A1 contains "1",B1 contains "2", A2 contains "3", B2 contains "4".
Cell A3 contains the following formula "=A1+B1".
If I copy the formula to the A4 cell under excel, it becomes "=A2+B2" : excel is adapting the content of the formula dynamically.
Unfortunately I cannot get the same result programatically. The only solution I found is to tokenize the formula and do the dirty work myself, but I really doubt that this is supposed to be done that way. I was not able to find what I'm looking for in the guides or in the API.
Is there an easier way to solve this problem ? If it's the case, can you please point me in the right direction ?
Best regards,
Nils
In my sense, user2622016 is right, except his solution manages only cell references, as opposed to area references (it won't work for =SUM(A1:B8) for instance).
Here's how I fixed this :
private void copyFormula(Sheet sheet, Cell org, Cell dest) {
if (org == null || dest == null || sheet == null
|| org.getCellType() != Cell.CELL_TYPE_FORMULA)
return;
if (org.isPartOfArrayFormulaGroup())
return;
String formula = org.getCellFormula();
int shiftRows = dest.getRowIndex() - org.getRowIndex();
int shiftCols = dest.getColumnIndex() - org.getColumnIndex();
XSSFEvaluationWorkbook workbookWrapper =
XSSFEvaluationWorkbook.create((XSSFWorkbook) sheet.getWorkbook());
Ptg[] ptgs = FormulaParser.parse(formula, workbookWrapper, FormulaType.CELL
, sheet.getWorkbook().getSheetIndex(sheet));
for (Ptg ptg : ptgs) {
if (ptg instanceof RefPtgBase) // base class for cell references
{
RefPtgBase ref = (RefPtgBase) ptg;
if (ref.isColRelative())
ref.setColumn(ref.getColumn() + shiftCols);
if (ref.isRowRelative())
ref.setRow(ref.getRow() + shiftRows);
} else if (ptg instanceof AreaPtg) // base class for range references
{
AreaPtg ref = (AreaPtg) ptg;
if (ref.isFirstColRelative())
ref.setFirstColumn(ref.getFirstColumn() + shiftCols);
if (ref.isLastColRelative())
ref.setLastColumn(ref.getLastColumn() + shiftCols);
if (ref.isFirstRowRelative())
ref.setFirstRow(ref.getFirstRow() + shiftRows);
if (ref.isLastRowRelative())
ref.setLastRow(ref.getLastRow() + shiftRows);
}
}
formula = FormulaRenderer.toFormulaString(workbookWrapper, ptgs);
dest.setCellFormula(formula);
}
I still don't know if I had it correct for all cell formulas, but it works for me, fast and reliable.
I too think that there isn't an easy way to do this.
Even the HSSF and XSSD examples on the POI site e.g. TimesheetDemo do the formula construction manually. e.g. around line 110
String ref = (char)('A' + j) + "3:" + (char)('A' + j) + "12";
cell.setCellFormula("SUM(" + ref + ")");
I looked inside FormulaEvaluator class and found some POI internal classes that can do the work for us.
FormulaParser, which parses String to array of "parse things":
String formula = cell.getCellFormula();
XSSFEvaluationWorkbook workbookWrapper =
XSSFEvaluationWorkbook.create((XSSFWorkbook) workbook);
/* parse formula */
Ptg[] ptgs = FormulaParser.parse(formula, workbookWrapper,
FormulaType.CELL, 0 /*sheet index*/ );
ptgs is now our formula in reverse polish notation. Now go through all elements and modify references one by one as you wish:
/* re-calculate cell references */
for( Ptg ptg : ptgs )
if( ptg instanceof RefPtgBase ) //base class for cell reference "things"
{
RefPtgBase ref = (RefPtgBase)ptg;
if( ref.isColRelative() )
ref.setColumn( ref.getColumn() + 0 );
if( ref.isRowRelative() )
ref.setRow( ref.getRow() + 1 );
}
And you're ready to render "parse things" back to String:
formula = FormulaRenderer.toFormulaString(workbookWrapper, ptgs);
cell.setCellFormula( formula );
Another way to copy formula relatively, tested with poi 3.12
public static void copyCellFormula(Workbook workbook, int sheetIndex, int rowIndex, int sourceColumnIndex, int destinationColumnIndex){
XSSFEvaluationWorkbook formulaParsingWorkbook = XSSFEvaluationWorkbook.create((XSSFWorkbook) workbook);
SharedFormula sharedFormula = new SharedFormula(SpreadsheetVersion.EXCEL2007);
Sheet sheet = workbook.getSheetAt(sheetIndex);
Row lookupRow = sheet.getRow(rowIndex);
Cell sourceCell = lookupRow.getCell(sourceColumnIndex);
Ptg[] sharedFormulaPtg = FormulaParser.parse(sourceCell.getCellFormula(), formulaParsingWorkbook, FormulaType.CELL, sheetIndex);
Ptg[] convertedFormulaPtg = sharedFormula.convertSharedFormulas(sharedFormulaPtg, 0, 1);
Cell destinationCell = lookupRow.createCell(destinationColumnIndex);
destinationCell.setCellFormula(FormulaRenderer.toFormulaString(formulaParsingWorkbook, convertedFormulaPtg));
}
Update shared formula as needed:
sharedFormula.convertSharedFormulas(sharedFormulaPtg, rowIndexOffset, columnIndexOffset);
As of poi 3.12, SharedFormula doesn't support cell reference/formula from other sheets (='Sheet1'!A1). Here's an update to SharedFormula:
public class SharedFormula {
private final int _columnWrappingMask;
private final int _rowWrappingMask;
public SharedFormula(SpreadsheetVersion ssVersion) {
this._columnWrappingMask = ssVersion.getLastColumnIndex();
this._rowWrappingMask = ssVersion.getLastRowIndex();
}
public Ptg[] convertSharedFormulas(Ptg[] ptgs, int formulaRow, int formulaColumn) {
Ptg[] newPtgStack = new Ptg[ptgs.length];
RefPtgBase areaNPtg = null;
AreaPtgBase var9 = null;
Object ptg = null;
byte originalOperandClass = 0;
for(int k = 0; k < ptgs.length; ++k) {
ptg = ptgs[k];
originalOperandClass = -1;
if(!((Ptg)ptg).isBaseToken()) {
originalOperandClass = ((Ptg)ptg).getPtgClass();
}
if(ptg instanceof RefPtgBase) {
if(ptg instanceof Ref3DPxg) {
areaNPtg = (Ref3DPxg)ptg;
this.fixupRefRelativeRowAndColumn(areaNPtg, formulaRow, formulaColumn);
ptg = areaNPtg;
}else if(ptg instanceof Ref3DPtg) {
areaNPtg = (Ref3DPtg)ptg;
this.fixupRefRelativeRowAndColumn(areaNPtg, formulaRow, formulaColumn);
ptg = areaNPtg;
}else {
areaNPtg = (RefPtgBase)ptg;
ptg = new RefPtg(this.fixupRelativeRow(formulaRow, areaNPtg.getRow(), areaNPtg.isRowRelative()), this.fixupRelativeColumn(formulaColumn, areaNPtg.getColumn(), areaNPtg.isColRelative()), areaNPtg.isRowRelative(), areaNPtg.isColRelative());
}
((Ptg)ptg).setClass(originalOperandClass);
}else if(ptg instanceof AreaPtgBase) {
if(ptg instanceof Area3DPxg) {
var9 = (Area3DPxg)ptg;
this.fixupAreaRelativeRowAndColumn(var9, formulaRow, formulaColumn);
ptg = var9;
}else if(ptg instanceof Area3DPxg) {
var9 = (Area3DPtg)ptg;
this.fixupAreaRelativeRowAndColumn(var9, formulaRow, formulaColumn);
ptg = var9;
}else {
var9 = (AreaPtgBase)ptg;
ptg = new AreaPtg(this.fixupRelativeRow(formulaRow, var9.getFirstRow(), var9.isFirstRowRelative()), this.fixupRelativeRow(formulaRow, var9.getLastRow(), var9.isLastRowRelative()), this.fixupRelativeColumn(formulaColumn, var9.getFirstColumn(), var9.isFirstColRelative()), this.fixupRelativeColumn(formulaColumn, var9.getLastColumn(), var9.isLastColRelative()), var9.isFirstRowRelative(), var9.isLastRowRelative(), var9.isFirstColRelative(), var9.isLastColRelative());
}
((Ptg)ptg).setClass(originalOperandClass);
}else if(ptg instanceof OperandPtg) {
ptg = ((OperandPtg)ptg).copy();
}
newPtgStack[k] = (Ptg)ptg;
}
return newPtgStack;
}
protected void fixupRefRelativeRowAndColumn(RefPtgBase areaNPtg, int formulaRow, int formulaColumn){
areaNPtg.setRow(this.fixupRelativeRow(formulaRow, areaNPtg.getRow(), areaNPtg.isRowRelative()));
areaNPtg.setColumn(this.fixupRelativeColumn(formulaColumn, areaNPtg.getColumn(), areaNPtg.isColRelative()));
areaNPtg.setRowRelative(areaNPtg.isRowRelative());
areaNPtg.setColRelative(areaNPtg.isColRelative());
}
protected void fixupAreaRelativeRowAndColumn(AreaPtgBase var9, int formulaRow, int formulaColumn){
var9.setFirstRow(this.fixupRelativeRow(formulaRow, var9.getFirstRow(), var9.isFirstRowRelative()));
var9.setLastRow(this.fixupRelativeRow(formulaRow, var9.getLastRow(), var9.isLastRowRelative()));
var9.setFirstColumn(this.fixupRelativeColumn(formulaColumn, var9.getFirstColumn(), var9.isFirstColRelative()));
var9.setLastColumn(this.fixupRelativeColumn(formulaColumn, var9.getLastColumn(), var9.isLastColRelative()));
var9.setFirstRowRelative(var9.isFirstRowRelative());
var9.setLastRowRelative(var9.isLastRowRelative());
var9.setFirstColRelative(var9.isFirstColRelative());
var9.setLastColRelative(var9.isLastColRelative());
}
protected int fixupRelativeColumn(int currentcolumn, int column, boolean relative) {
return relative?column + currentcolumn & this._columnWrappingMask:column;
}
protected int fixupRelativeRow(int currentrow, int row, boolean relative) {
return relative?row + currentrow & this._rowWrappingMask:row;
}
}
I don't think there is. POI would have to parse the formula (taking into account A1 vs. $A$1 vs. $A1 etc.) and I don't believe it has that capacity. When I've done this in the past I've always had to manage this myself. Sorry - not the answer you hoped for!
you can try some third party excel librarys,most of them can handle the relative/absolute range formulas.

Categories