How to save an xslm file as xslx in Apache POI - apache-poi

All:
I am pretty new to Excel and APche POI, I wonder how to read in Excel .xlsm file(Macro Enable excel) and save it as .xlsx file using Apache POI?
Any example will be appreciated

Making an answer from my comments. Hope it will be more clear then.
The following code does creating a XSSFWorkbook from a Workbook.xlsm template which remains unchanged.
It does changings in this workbook then and, before saving a copy as *.xlsx, the current state will be saved as WorkbookNew.xlsm file. So the macros stays preserved.
Then the VBA will be removed, the content type will be set to XLSX and further changings will be made. Then this copy will be saved as WorkbookNew.xlsx file.
After that, the previous workbook state will be got back by creating the workbook again from the previous saved WorkbookNew.xlsm file. Then further changings will be made and after all the final state of the WorkbookNew.xlsm file will be written out.
So we have the unchanged Workbook.xlsm template, the WorkbookNew.xlsx and the WorkbookNew.xlsm then.
Example:
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.regex.Pattern;
class ReadXSLMWriteXLSXWorkbook {
public static void main(String[] args) throws Exception {
XSSFWorkbook workbook;
Sheet sheet;
Row row;
Cell cell;
FileOutputStream out;
//create workbook from XLSM template
workbook = (XSSFWorkbook)WorkbookFactory.create(new FileInputStream("Workbook.xlsm"));
//do changings
sheet = workbook.getSheetAt(0);
row = sheet.getRow(0);
if (row == null) row = sheet.createRow(0);
cell = row.getCell(0);
if (cell == null) cell = row.createCell(0);
cell.setCellValue("changed in XLSM before writing as XLSX");
//write out the current state
out = new FileOutputStream("WorkbookNew.xlsm");
workbook.write(out);
out.close();
//save copy as XLSX ----------------START
//remove VBA
OPCPackage opcpackage = workbook.getPackage();
//get and remove the vbaProject.bin part from the package
PackagePart vbapart = opcpackage.getPartsByName(Pattern.compile("/xl/vbaProject.bin")).get(0);
opcpackage.removePart(vbapart);
//get and remove the relationship to the removed vbaProject.bin part from the package
PackagePart wbpart = workbook.getPackagePart();
PackageRelationshipCollection wbrelcollection = wbpart.getRelationshipsByType("http://schemas.microsoft.com/office/2006/relationships/vbaProject");
for (PackageRelationship relship : wbrelcollection) {
wbpart.removeRelationship(relship.getId());
}
//set content type to XLSX
workbook.setWorkbookType(XSSFWorkbookType.XLSX);
//do changings only in XLSX
sheet = workbook.getSheetAt(0);
row = sheet.getRow(1);
if (row == null) row = sheet.createRow(1);
cell = row.getCell(1);
if (cell == null) cell = row.createCell(1);
cell.setCellValue("changed before writing as XLSX");
//write out the XLSX
out = new FileOutputStream("WorkbookNew.xlsx");
workbook.write(out);
out.close();
//save copy as XLSX ----------------END
//get back the previous saved state
workbook = (XSSFWorkbook)WorkbookFactory.create(new FileInputStream("WorkbookNew.xlsm"));
//do changings
sheet = workbook.getSheetAt(0);
row = sheet.getRow(2);
if (row == null) row = sheet.createRow(1);
cell = row.getCell(2);
if (cell == null) cell = row.createCell(1);
cell.setCellValue("changed in XLSM after writing as XLSX");
//write out the XLSM
out = new FileOutputStream("WorkbookNew.xlsm");
workbook.write(out);
out.close();
workbook.close();
}
}

Related

Apache-poi how to unhide column upon creation of Excel file

I am trying to generate an Excel workbook which will be a template.
For now I am trying to generate a workbook with 1 sheet that holds only header cells with values, with certain Height and Width values. The problem is not that I cannot do it, but when I generate/create the .xlsx file the cells are hidden in a certain way and I have to click N(if there are 13 cells) times to display them all.
[Example of how Cells are hidden]
[1]: https://i.stack.imgur.com/xYh1P.png
And the way I want them to be displayed upon creation of the file is like this.
[Example of how I wish them to be displayed uppon creation]
[2]: https://i.stack.imgur.com/FWILw.png
The code is as follows
//creating workbook
private static void createWorkBookFile() throws IOException {
String filePath = "C:\\UltimateMapper\\UltimateMapperProject\\";
filePath+="\\WriteTestFiles";
System.out.print("Enter name of file: ");
String fileName = scan.nextLine();
filePath+="\\"+fileName+".xlsx";
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet currentSheet = workbook.createSheet("File to STG");
XSSFRow row;
XSSFCell cell;
//TO DO START FORM HERE FINISH AND THEN INSIDE LOOP
String[] fileToSTGCellValues_Names = new String[] {"Source Location_Schema","Source File_Table Name",
"Source_Field_Column Name","Start Pos","End Pos",
"Source Field Length","Source Field_Column Data Type",
"Transformation","Target Location_Schema","Target File_Table Name",
"Target Field_Column Name","Target Field_Column Data Type","Comments"};
HashMap<String,Integer> fileToSTGCellValues_Widths = new HashMap<String,Integer>();
fileToSTGCellValues_Widths.put("Source Location_Schema",26);
fileToSTGCellValues_Widths.put("Source File_Table Name",26);
fileToSTGCellValues_Widths.put("Source_Field_Column Name",35);
fileToSTGCellValues_Widths.put("Start Pos",10);
fileToSTGCellValues_Widths.put("End Pos",10);
fileToSTGCellValues_Widths.put("Source Field Length",18);
fileToSTGCellValues_Widths.put("Source Field_Column Data Type",21);
fileToSTGCellValues_Widths.put("Transformation",43);
fileToSTGCellValues_Widths.put("Target Location_Schema",18);
fileToSTGCellValues_Widths.put("Target File_Table Name",36);
fileToSTGCellValues_Widths.put("Target Field_Column Name",36);
fileToSTGCellValues_Widths.put("Target Field_Column Data Type",20);
fileToSTGCellValues_Widths.put("Comments",47);
int headeRowNumber = 0;
row = currentSheet.createRow(headeRowNumber);
row.setHeightInPoints(28.50f);
for(int i =0;i<13;i++) {
currentSheet.setColumnWidth(i, fileToSTGCellValues_Widths.get(fileToSTGCellValues_Names[i]));
cell = row.createCell(i);
cell.setCellValue(fileToSTGCellValues_Names[i]);
}
FileOutputStream fout = new FileOutputStream(filePath);
workbook.write(fout);
fout.close();
System.out.println("File created");
}```

Finding difficulty to add one more sheet in Excel workbook using Apache POI

My following 3 line code is used to create one file with sheet1(Year 2019) now would like to execute another page and need to store the result of it in same file as sheet2(Year 2020).
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet sheet = wb.createSheet("Year 2019");
FileOutputStream fos = new FileOutputStream("C:\\Users\\dp\\Desktop\\MData1_Test_1.xlsx");
Row header_1 = sheet.createRow(rowNum[0]);
rowNum[0] = (rowNum[0] + 1);
header_1.createCell(0).setCellValue("Analytics");
Any help will be appreciated.
You can do something like this:
// open your first file
try (InputStream inp = new FileInputStream(fut.get())) {
Workbook wb = WorkbookFactory.create(inp);
// get sheet by name
Sheet sheet = wb.getSheet("Year 2019");
if (null != sheet) {
// if sheet exists => delete it
int index = wb.getSheetIndex(String name);
wb.removeSheetAt(index);
}
// create new sheet
sheet = wb.createSheet("Year 2019");
// proceed adding data
// row = sheet.createRow(0);
// row.createCell(0).setCellValue("data");
// ...
}
You can repeat these steps as many time as you need to manage as many sheets as you want.

How to fix "The supplied data appears to be in the Office 2007+ XML."

This is my code that extracts value from an xlsx file and print it on Eclipse console
public class testcode {
public void readexcel(String filepath, String filename, String sheetname) throws IOException
{
//Create an object of file class to open xlsx file
File file = new File(filepath+"\\"+filename);
//Create an object of FileInputStream to read an xlsx file
FileInputStream inputstream = new FileInputStream(file);
Workbook workbook = null;
//Find file extension name by using substring
String FileExtensionName = filename.substring(filename.indexOf("."));
//Check condition whether file is xlsx or xls
if(FileExtensionName.equalsIgnoreCase("xlsx"))
workbook = new XSSFWorkbook(inputstream);
else
workbook = new HSSFWorkbook(inputstream);
//Read sheet inside the workbook by its name
Sheet sheet = workbook.getSheet(sheetname);
//Find number of rows in sheet
int rowCount = sheet.getLastRowNum() - sheet.getFirstRowNum();
//Create a loop over all the rows of excel file to read it
for(int i = 0; i<rowCount+1;i++)
{
Row row = sheet.getRow(i);
//Create loop to print cell values in a row
for(int j = 0; j<row.getLastCellNum();j++)
{
//Print excel value in console System.out.println(row.getCell(j).getStringCellValue()+"||");
}
System.out.println();
}
}
public static void main(String[] args) throws IOException {
testcode objExcelFile = new testcode();
//Prepare path of excel file
String filepath = "C:\\Users\\malfoy\\Desktop";
objExcelFile.readexcel(filepath,"testfile.xlsx", "read");
}
}
I am using office 2007 edition and I am getting an exception which says
"The supplied data appears to be in the Office 2007+ XML. You are calling the part of POI that deals with OLE2 Office Documents. You need to call a different part of POI to process this data (eg XSSF instead of HSSF)"
How to fix it?
The line
String FileExtensionName = filename.substring(filename.indexOf("."));
returns a value with the dot (in your case ".xlsx")
So the following if statement returns a HSSFWorkbook instance instead of XSSFWorkbook.
To correct it use
String FileExtensionName = filename.substring(filename.lastIndexOf(".")+1);

apache POI: dataValidation (or style) for entire column, except for the header row?

For the CellRange we can pass -1 for both the start/end row parameters to apply styles and dataValidators to the entire column.
But how to skip the header?
The ideal solution would be a CellRangeAddressList created with "A1:A$", but it only have int constructors.
i tried assuming that -1 is a special value that means something special, but CellRangeAddressList(1, -1, ...) fails with a "start row > finish row" error. Then I also tried assuming -1 meant last cell, but going from last to 1 CellRangeAddressList(-1, 1, ...) resulted in no cell selected.
Lastly I tried to remove the first row from the CellRangeAddressList(-1, -1, ...) but it is not possible to manipulate the ranges after creation as far as I could tell from the docs.
Creating a CellRangeAddress for whole column except first row means a CellRangeAddress starts on row 2 and goes up to maximum rows count. This depends on SpreadsheetVersion. In EXCEL2007 the maximum rows count is 2^20 = 1048576. In EXCEL97 the maximum rows count is 2^16 = 65536.
Using SpreadsheetVersion we can get that different maximum rows count dependent on SpreadsheetVersion.
Example:
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.ss.SpreadsheetVersion;
class CreateCellRangeAddressList {
public static void main(String[] args) throws Exception {
//Workbook workbook = new XSSFWorkbook();
Workbook workbook = new HSSFWorkbook();
// ...
int lastRow = workbook.getSpreadsheetVersion().getLastRowIndex();
CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(
1, // row 2
lastRow,
2, // column C
2);
System.out.println(cellRangeAddressList.getCellRangeAddress(0));
//C2:C1048576 or C2:C65536 dependent on SpreadsheetVersion
// ...
}
}
Because the question was about data validation for whole column except first row let's have a example for this.
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.util.CellRangeAddressList;
class CreateExcelDataValidationListsWholeColumn {
public static void main(String[] args) throws Exception {
//Workbook workbook = new HSSFWorkbook();
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Sheet1");
sheet.createRow(0).createCell(1).setCellValue("col2Head");
//data validation in column B, except first row:
DataValidationHelper dvHelper = sheet.getDataValidationHelper();
DataValidationConstraint dvConstraint = dvHelper.createExplicitListConstraint(new String[]{"X", "Y"}) ;
int lastRow = workbook.getSpreadsheetVersion().getLastRowIndex();
CellRangeAddressList addressList = new CellRangeAddressList(1, lastRow, 1, 1); //B2:B1048576
DataValidation validation = dvHelper.createValidation(dvConstraint, addressList);
sheet.addValidationData(validation); // data validation for B2:B1048576
FileOutputStream out = null;
if (workbook instanceof HSSFWorkbook) {
out = new FileOutputStream("CreateExcelDataValidationListsWholeColumn.xls");
} else if (workbook instanceof XSSFWorkbook) {
out = new FileOutputStream("CreateExcelDataValidationListsWholeColumn.xlsx");
}
workbook.write(out);
workbook.close();
out.close();
}
}
This results in sheet XML as follows:
<worksheet>
<dimension ref="B1"/>
<sheetViews>
<sheetView workbookViewId="0" tabSelected="true"/>
</sheetViews>
<sheetFormatPr defaultRowHeight="15.0"/>
<sheetData>
<row r="1"><c r="B1" t="s"><v>0</v></c></row>
</sheetData>
<dataValidations count="1">
<dataValidation type="list" sqref="B2:B1048576" allowBlank="true" errorStyle="stop">
<formula1>"X,Y"</formula1>
</dataValidation>
</dataValidations>
<pageMargins bottom="0.75" footer="0.3" header="0.3" left="0.7" right="0.7" top="0.75"/>
</worksheet>
And using HSSFWorkbook the resulting CreateExcelDataValidationListsWholeColumn.xls is 4 KByte in size.

dropdown Validation not working if it exceeds 50 rows in the Export To Excel

I am generating Excel File(.xlsx) using apache poi jar (poi-ooxml-3.9.jar), I added dropdown validation for 10 columns in my excel file, If I generate the Excel File with 50 rows, drop down validation is working. If it exceeds more than 50 rows, drop down validation is not coming in the Excel File, When I open the excel File I get the message as "We found a problem with some content in fileName.xlsx. Do you want us to try to recover as much as we can ? If you trust the source of this workbook, click Yes ". when click on Yes, all the dropdown validation it is removing. Kindly need solution to fix this issue.
Do not create DataValidationConstraint for each single cell but only for each varying list you need. Then create DataValidation using those DataValidationConstraint for continuous CellRangeAddressList which are as big as possible and also are not all single cells.
Example creates ten different list validations for column 1 to 10 in rows 1 to 10000.
import java.io.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;
class DataValidationList {
public static void main(String[] args) throws Exception {
Workbook workbook = new XSSFWorkbook(); // or new HSSFWorkbook
Sheet sheet = workbook.createSheet("Data Validation");
DataValidationHelper dvHelper = sheet.getDataValidationHelper();
for (int col = 0; col < 10; col++) {
DataValidationConstraint dvConstraint = dvHelper.createExplicitListConstraint(
new String[]{"Col "+(col+1)+" one","Col "+(col+1)+" two","Col "+(col+1)+" three"});
CellRangeAddressList addressList = new CellRangeAddressList(0, 9999, 0, col);
DataValidation validation = dvHelper.createValidation(
dvConstraint, addressList);
if(validation instanceof XSSFDataValidation) {
validation.setSuppressDropDownArrow(true);
validation.setShowErrorBox(true);
}
else {
validation.setSuppressDropDownArrow(false);
}
sheet.addValidationData(validation);
}
String filename;
if(workbook instanceof XSSFWorkbook) {
filename = "DataValidationList.xlsx";
} else {
filename = "DataValidationList.xls";
}
FileOutputStream out = new FileOutputStream(filename);
workbook.write(out);
out.close();
workbook.close();
}
}

Resources