I want to write a MySQL Data into Excel file. In that, I need to create table border for my data as well need to merging the few column headers.
I have done the mapping to Load the MySQL data into Excel Sheet. But I don't know the way to create table border as well merging the column headers.
Below code will help me to Merge the cells, But how to incorporate this code in between my two talend components,
tMySQLInput -> tFileOutputExcel
import java.io.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
public class MergeCellsAcrossColumns {
public static void main(String[] args) throws Exception{
/* Create Workbook and Worksheet */
HSSFWorkbook my_workbook = new HSSFWorkbook();
HSSFSheet my_sheet = my_workbook.createSheet("Merge Cells");
Row row = my_sheet.createRow((short) 1);
Cell cell = row.createCell((short) 1);
cell.setCellValue("Merge Data with Apache POI");
my_sheet.addMergedRegion(new CellRangeAddress(
1, // mention first row here
1, //mention last row here, it is 1 as we are doing a column wise merging
1, //mention first column of merging
5 //mention last column to include in merge
));
/* Write changes to the workbook */
FileOutputStream out = new FileOutputStream(new File("C:\\Merge_Across_Columns.xls"));
my_workbook.write(out);
out.close();
}
}
you can use tJavaRow between your components. This component allows you to write java code and transform data. this component has input and output schema where you can specify input this component will take and output this component will give.
section below for import will move to Advance Settings section of tJavaRow.
import java.io.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
You can write your java code in BAsic Settings section
your refer to input data schema column by
input_row.column_name
and output as output_row.column_name
...(try to user GenerateCode option to see how input_row and output_row works)
Ideally for merging/transforming data you can also use tMap which can merge/transform rows and output the data to next level
Related
I'm trying to remove a row in a excel sheet using java.
But my code isn't removing anything.
This is my code for removing the last row.
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.usermodel.Sheet;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
final String filepath = "data-DB.xlsx";
File workbookFile = new File(filepath);
FileInputStream in = new FileInputStream(workbookFile);
Workbook database = WorkbookFactory.create(in);
Sheet sheet = database.getSheet("Users");
int lastRow = sheet.getLastRowNum();
Row row = sheet.getRow(lastRow);
sheet.removeRow(row);
}
}
This line should get the row
Row row = sheet.getRow(lastRow);
This should remove the row.
sheet.removeRow(row);
What am I doing wrong?
The documentation for getLastRowNum says :
Gets the last row on the sheet Note: rows which had content before and
were set to empty later might still be counted as rows by Excel and
Apache POI, so the result of this method will include such rows and
thus the returned value might be higher than expected!
So most probably you'll get getting a row number which is empty already and you are trying to remove that, and you'r seeing that removeRow is not working.
Print or debug the value of lastRow to fix the error
The application I am working on creates Excel exports using Apache POI. It was brought to our attention, through a security audit, that cells containing malicious values can spawn arbitrary processes if the user is not careful enough.
To reproduce, run the following:
import java.io.FileOutputStream;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
public class BadWorkbookCreator {
public static void main(String[] args) throws Exception {
try(
Workbook wb = new HSSFWorkbook();
FileOutputStream fos = new FileOutputStream("C:/workbook-bad.xls")
) {
Sheet sheet = wb.createSheet("Sheet");
Row row = sheet.createRow(0);
row.createCell(0).setCellValue("Aaaaaaaaaa");
row.createCell(1).setCellValue("-2+3 +cmd|'/C calc'!G20");
wb.write(fos);
}
}
}
Then open the resulting file:
And follow these steps:
Click on (A) to select the cell with malicious content
Click on (B) so that the cursor is in the formula editor
Press ENTER
You will be asked if you allow Excel to run an external application; if you answer yes, Calc is launched (or any malicious code)
One may say that the user is responsible for letting Excel run arbitrary things and the user was warned. But still, the Excel is downloaded from a trusted source and someone may fall into the trap.
Using Excel, you can place a single quote in front of the text in the formula editor to escape it. Placing the single quote in the cell content programmatically (e.g. code as below) makes the single quote visible!
String cellValue = cell.getStringCellValue();
if( cellValue != null && "=-+#".indexOf(cellValue.charAt(0)) >= 0 ) {
cell.setCellValue("'" + cellValue);
}
The question: Is there a way to keep the value escaped in the formula editor, but show the correct value, without the leading single quote, in the cell?
Thanks to the hard work investigating of Axel Richter here and Nikos Paraskevopoulos here....
From Apache POI 3.16 beta 1 onwards (or for those who live dangerously, any nightly build after 20161105), there are handy methods on CellStyle for getQuotePrefixed and setQuotePrefixed(boolean)
Your code could then become:
// Do this once for the workbook
CellStyle safeFormulaStyle = workbook.createCellStyle();
safeFormulaStyle.setQuotePrefixed(true);
// Per cell
String cellValue = cell.getStringCellValue();
if( cellValue != null && "=-+#".indexOf(cellValue.charAt(0)) >= 0 ) {
cell.setCellStyle(safeFormulaStyle);
}
Thanks to the instant (kudos) response from the POI team (see accepted answer), this solution should be obsolete. Keeping it as a reference, could be useful in cases an upgrade to POI >= 3.16 is not possible.
Thanks to the comment of Axel Richter (for which I am very-very thankful) I managed to work out a solution. It is definitely NOT as straightforward as in the case of XLSX files (XSSFWorkbook), because it involves creating the org.apache.poi.hssf.model.InternalWorkbook by hand; this class is marked as #Internal by the POI project, but is public as far as Java is concerned. Additionally, the field that is set to correct the problem, i.e. ExtendedFormatRecord.set123Prefix(true) is not documented!
Here is the solution, for what it's worth - compare it with the code in the question:
import java.io.FileOutputStream;
import org.apache.poi.hssf.model.InternalWorkbook;
import org.apache.poi.hssf.record.ExtendedFormatRecord;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
public class GoodWorkbookCreator {
public static void main(String[] args) throws Exception {
InternalWorkbook internalWorkbook = InternalWorkbook.createWorkbook();
try(
HSSFWorkbook wb = HSSFWorkbook.create(internalWorkbook);
FileOutputStream fos = new FileOutputStream("C:/workbook-good.xls")
) {
HSSFCellStyle style = (HSSFCellStyle) wb.createCellStyle();
ExtendedFormatRecord xfr = internalWorkbook.getExFormatAt(internalWorkbook.getNumExFormats() - 1);
xfr.set123Prefix(true); // THIS IS WHAT IT IS ALL ABOUT
Sheet sheet = wb.createSheet("Sheet");
Row row = sheet.createRow(0);
row.createCell(0).setCellValue("Aaaaaaaaaa");
row.createCell(1).setCellValue("-2+3 +cmd|'/C calc'!G20");
Cell cell = row.createCell(2);
cell.setCellValue("-2+3 +cmd|'/C calc'!G20");
cell.setCellStyle(style);
wb.write(fos);
}
}
}
I am currently working on the automation of Excel, and add such I have made a good use of the Apache POI library.
As I have so much data stored in my excel workbook in various columns, that I'm trying to create a pivot table.
Is there any way to create Pivot tables using POI ?
My requirement is that I need to create the pivot table in a new excel workbook or in the same workbook where I store my data.
The 'Quick Guide' is quite out of date.
The change log refers to this bugzilla issue as resolved.
You can see the code here:
Here is a snippet:
public static void main(String[] args) throws FileNotFoundException, IOException, InvalidFormatException {
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet sheet = (XSSFSheet) wb.createSheet();
//Create some data to build the pivot table on
setCellData(sheet);
XSSFPivotTable pivotTable = sheet.createPivotTable(new AreaReference("A1:D4"), new CellReference("H5"));
//Configure the pivot table
//Use first column as row label
pivotTable.addRowLabel(0);
//Sum up the second column
pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 1);
//Set the third column as filter
pivotTable.addColumnLabel(DataConsolidateFunction.AVERAGE, 2);
//Add filter on forth column
pivotTable.addReportFilter(3);
FileOutputStream fileOut = new FileOutputStream("ooxml-pivottable.xlsx");
wb.write(fileOut);
fileOut.close();
}
No you cant.refer here
• Charts You can not currently create charts. You can however create
a chart in Excel, modify the chart data values using HSSF and write a
new spreadsheet out. This is possible because POI attempts to keep
existing records intact as far as possible.
• Macros Macros can not be created. However, reading and re-writing
files containing macros will safely preserve the macros.
• Pivot Tables Generating pivot tables is not supported. It has been
reported that files containing pivot tables can be read and re-written
safely.
yes, you can create. Dependency required
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.15</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>ooxml-schemas</artifactId>
<version>1.3</version>
</dependency>
Input Excel file
Java code to create pivot table on same sheet
import java.io.File;
import java.io.FileOutputStream;
import java.io.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.*;
import org.apache.poi.xssf.usermodel.*;
public class Test {
public static void main(String[] args) throws Exception{
/* Read the input file that contains the data to pivot */
FileInputStream input_document = new FileInputStream(new File("input-file-path\\Pivot-Cube.xlsx"));
/* Create a POI XSSFWorkbook Object from the input file */
XSSFWorkbook my_xlsx_workbook = new XSSFWorkbook(input_document);
/* Read Data to be Pivoted - we have only one worksheet */
XSSFSheet sheet = my_xlsx_workbook.getSheetAt(0);
/* Get the reference for Pivot Data */
AreaReference a=new AreaReference("A1:C5");
/* Find out where the Pivot Table needs to be placed */
CellReference b=new CellReference("I5");
/* Create Pivot Table */
XSSFPivotTable pivotTable = sheet.createPivotTable(a,b, sheet);
/* Add filters */
pivotTable.addReportFilter(0);
pivotTable.addRowLabel(1);
pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 2);
/* Write Pivot Table to File */
FileOutputStream output_file = new FileOutputStream(new File("output-file-path\\POI_XLS_Pivot_Example.xlsx"));
my_xlsx_workbook.write(output_file);
input_document.close();
}
}
I have a pptx template, it has just 1 slide for testing purpose. The slide has a simple bar chart. I am able to edit the bar chart by double clicking it on pptx file and I could change the values in Sheet1 (Data sheet for Barchart), and, I able to see the changes immediately in BarChart.
Now, I am trying to do the same using POI API. I am doing the below steps here
Read the template file = "MyTemplate.pptx" - https://docs.google.com/file/d/0B-q0lBy0lKLic3dCSUVsZUdGQzA/edit?usp=sharing
Have all shapes in Map
Read the BarChart shape by referring it's name - "MyBarChart"
Read the excel file of the BarChart
Update a cell Value in Sheet1
Save everything and write into another file - "MyPresentation.pptx"
When I open the file - "MyPresentation.pptx", it does not show up the updated cell value upfront in the Bar. I need to double click the chart to change it to EDIT mode to get the latest value reflected. Why does BarChart is not getting refreshed when it's underlying Data Sheet is updated using POI?
Any suggestion to solve the issue?
Here is the completed code, attached pptx template file as well.
package com.ppt;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFGraphicFrame;
import org.apache.poi.xslf.usermodel.XSLFShape;
import org.apache.poi.xslf.usermodel.XSLFSheet;
import org.apache.poi.xslf.usermodel.XSLFSlide;
public class PPTChart {
public static void main(String args[]) throws InvalidFormatException, IOException{
XMLSlideShow ppt;
// Read pptx template
ppt = new XMLSlideShow(new FileInputStream("MyTemplate.pptx"));
// Get all slides
XSLFSlide[] slide = ppt.getSlides();
// Get working slide that is slide=0
XSLFSlide slide0 = slide[0];
XSLFShape[] shapes = slide0.getShapes();
// Add all shapes into a Map
Map <String, XSLFShape> shapesMap = new HashMap<String, XSLFShape>();
for(XSLFShape shape : shapes)
{
shapesMap.put(shape.getShapeName(), shape);
System.out.println(shape.getShapeName() + " " + shape.getShapeId() + " " + shape);
}
// Read the bar chart
XSLFGraphicFrame chart = (XSLFGraphicFrame) shapesMap.get("MyBarChart");
// Get the chart sheet
XSLFSheet sheet = chart.getSheet();
for(int i=0; i<sheet.getRelations().size(); i++)
{
System.out.println("Partname =" + sheet.getRelations().get(i).getPackagePart().getPartName());
if(sheet.getRelations().get(i).getPackagePart().getPartName().toString().contains(".xls"))
{
System.out.println("Found the bar chart excel");
// BarChart Excel package part
PackagePart barChartExcel = sheet.getRelations().get(i).getPackagePart();
// Reference the excel in workbook
HSSFWorkbook wb = new HSSFWorkbook(barChartExcel.getInputStream());
// Read sheet where Barchart data is available
HSSFSheet mysheet = wb.getSheetAt(1);
// Read first
HSSFRow row = mysheet.getRow(1);
//Print first cell value for debugging
System.out.println("Updating cell value from - " + row.getCell(1));
// New value
double insertValue = 7777777.0;
wb.getSheetAt(1).getRow(1).getCell(1).setCellValue(insertValue);
// Set first BarChart as active sheet
HSSFSheet mysheet0 = wb.getSheetAt(0);
mysheet0.setActive(true);
// Write the updated excel back to workbook
OutputStream excelOut = barChartExcel.getOutputStream();
excelOut.flush();
wb.write(excelOut);
excelOut.close();
// Write workbook to file
FileOutputStream o = new FileOutputStream("MyPresentation.pptx");
ppt.write(o);
o.close();
System.out.println("new ppt is created....");
break; // Exit
}
}
}
}
I'm working on something similar right now. Check out the thread link below for actually updating the chart visuals. You have to modify the plot area portion of the underlying XML.
How can one programmatically read the graph values from a Powerpoint presentation using Apache's POI?
Here is the code you'd use to do it with pptx4j.
You ought to be able to convert that to equivalent POI code.
Note that the pptx4j code is updating an OpenXML spreadsheet, whereas your code is targeting the legacy binary format.
Does anyone know what could be wrong with the following filter I am trying to set for a report generated with apache POI?
I'm using this code:
sheet.setAutoFilter(CellRangeAddress.valueOf("A4:A6"));
To get this result:
However, when I click the arrow to filter my results I also get the value "average" as a possible result in the dropdown list.
Is there something I'm missing here?
Simply add an empty row between your data area and the footer row.
The data area can be limited by empty rows and columns/header.
Although you've selected A4:A6, only A4 was marked as autofilter ... I'm not sure, but I think, you can only achieve horizontal autofilter via VBA. So setAutoFilter should be something like A4:B4, as you mark only the header and not the data area.
(tested with POI 3.9, Libre Office 4.0)
import java.io.*;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.util.*;
public class Autofilter {
public static void main(String[] args) throws Exception {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet();
sheet.createRow(3).createCell(0).setCellValue("Protocol Number");
sheet.createRow(4).createCell(0).setCellValue("DEMONNUMBER1");
sheet.createRow(5).createCell(0).setCellValue("DEMONNUMBER2");
sheet.createRow(6).setZeroHeight(true);
sheet.createRow(7).createCell(0).setCellValue("Average");
sheet.setAutoFilter(CellRangeAddress.valueOf("A4:B4"));
FileOutputStream fos = new FileOutputStream("autofilter.xls");
wb.write(fos);
fos.close();
}
}