I am attempting to write an excel sheet using POI and hashMaps. My code successfully creates and populates an excel sheet but not all of the information is written to the sheet. In debug mode it seems to write 5 key, value pairs and then loops to the start at key [0]. Can someone tell me where the mistake is in my logic?
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet(make + " sheet");
int rowNum = 0;
ConcurrentHashMap <Integer, String[] > data = new
ConcurrentHashMap<Integer, String[]>();
data.put(rowNum++, new String[] {"VIN", "Make", "Model", "Year",
"Major Group", "Caption", "Cap Filter", "Illustration",
"Illus Filter", "PNC", "Part Name", "Part Number", "Quantity",
"Part Filter"});
for (Part p : plist){
String PNC = p.getPNC();
String quantity = p.getQuantity();
if(vFilterId.contains(p.getId())) {
data.put(rowNum++ , new String[] {vinId, make,
model, year, group, caption, capFilter, illusName,
iFilter, PNC, p.getName(), p.getPartNumber(),
quantity, "NONFILTERED"});
} else {
data.put(rowNum++ , new String[] {vinId, make,
model, year, group, caption, capFilter, illusName,
iFilter, PNC, p.getName(), p.getPartNumber(),
quantity, "NONFILTERED"});
}
}
int rowIndex = 0;
Set<Integer> keyset = data.keySet();
for (Integer key : keyset) {
Row row = sheet.createRow(rowIndex++);
Object[] objArr = data.get(key);
int cellIndex = 0;
for (Object obj : objArr) {
Cell cell = row.createCell(cellIndex++);
cell.setCellValue((String) obj);
}
}
try {
FileOutputStream fos = new FileOutputStream(outputFile);
workbook.write(fos);
fos.close();
System.out.println("XLS sheet written.");
} catch (IOException e) {
e.printStackTrace();
}
}
return ReturnConstants.SUCCESS;
}
Thanks in advance!
You're using a map to store data representing rows in a table. You'd be better off using a List since maps are generally not sorted (i.e. the order of the entries might change over time).
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet(make + " sheet");
List<String[]> data = new ArrayList<String[]>();
data.add(new String[] {"VIN", "Make", "Model", "Year",
"Major Group", "Caption", "Cap Filter", "Illustration",
"Illus Filter", "PNC", "Part Name", "Part Number", "Quantity",
"Part Filter"});
for (Part p : plist){
String PNC = p.getPNC();
String quantity = p.getQuantity();
if(vFilterId.contains(p.getId())) {
data.add(new String[] {vinId, make,
model, year, group, caption, capFilter, illusName,
iFilter, PNC, p.getName(), p.getPartNumber(),
quantity, "NONFILTERED"});
} else {
data.add(new String[] {vinId, make,
model, year, group, caption, capFilter, illusName,
iFilter, PNC, p.getName(), p.getPartNumber(),
quantity, "NONFILTERED"});
}
}
for (int rowIndex=0; rowIndex<data.size(); rowIndex++) {
Row row = sheet.createRow(rowIndex);
Object[] objArr = data.get(rowIndex);
int cellIndex = 0;
for (Object obj : objArr) {
Cell cell = row.createCell(cellIndex++);
cell.setCellValue((String) obj);
}
}
It's hard to determine without debugging your code, but from what you described it seems like your keyset variable contains only 3 entries, which is why you are outputting only 3 rows. So the first thing I would do would be to display (using System.out.println) data.size() and keyset.size() to see how big they are. I am guessing one or both are only of size 3.
Did you show all the relevant code? I think perhaps not, because, for example, your if statement seems redundant as you output the same thing regardless of whether you execute the if code or else clause.
I do agree with the first answer that there is no need to use a HashMap; an ArrayList will work just as well. But, as you discovered, that has nothing to do with why you are only seeing 3 rows.
Sorry I can't be more helpful, but I think some debugging on your part with System.out.println will go a long way in discovering what the problem is.
Related
I have defined a list of valuses my_list in one excel sheet as follow:
In another excel sheet, I reference for some cells to that list sothat this list is shown as dropdown in the cell as follows:
Using poi, I go throw excel sheet rows/columns and read cells for cell.
I get value of cells using method:
cell.getStringCellValue()
My question is how to get the name of the list my_list from the cell?
This problem contains multiple different problems.
First we need get sheet's data validations and then for each data validation get Excel cell ranges the data validation applies to. If the cell is in one of that cell ranges and if data validation is a list constraint then do further proceedings. Else return a default value.
If we have a explicit list like "item1, item2, item3, ..." then return this.
Else if we have a formula creating the list and is formula1 a area reference to a range in same sheet, then get all cells in that cell range and put their values in an array and return this.
Else if we have a formula creating the list and is formula1 a reference to a defined name in Excel, then get the Excel cell range the name refers to. Get all cells in that cell range and put their values in an array and return this.
Complete Example. The ExcelWorkbook contains the data validation in first sheet cell D1.
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.*;
import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import java.io.FileInputStream;
import java.util.List;
public class ExcelGetDataValidationList {
static String[] getDataFromAreaReference(AreaReference areaReference, Sheet sheet) {
DataFormatter dataFormatter = new DataFormatter();
Workbook workbook = sheet.getWorkbook();
CellReference[] cellReferences = areaReference.getAllReferencedCells(); // get all cells in that cell range
String[] listValues = new String[cellReferences.length]; // and put their values in an array
for (int i = 0 ; i < cellReferences.length; i++) {
CellReference cellReference = cellReferences[i];
if (cellReference.getSheetName() == null) {
listValues[i] = dataFormatter.formatCellValue(
sheet.getRow(cellReference.getRow()).getCell(cellReference.getCol())
);
} else {
listValues[i] = dataFormatter.formatCellValue(
workbook.getSheet(cellReference.getSheetName()).getRow(cellReference.getRow()).getCell(cellReference.getCol())
);
}
}
return listValues;
}
static String[] getDataValidationListValues(Sheet sheet, Cell cell) {
List<? extends DataValidation> dataValidations = sheet.getDataValidations(); // get sheet's data validations
for (DataValidation dataValidation : dataValidations) {
CellRangeAddressList addressList = dataValidation.getRegions(); // get Excel cell ranges the data validation applies to
CellRangeAddress[] addresses = addressList.getCellRangeAddresses();
for (CellRangeAddress address : addresses) {
if (address.isInRange(cell)) { // if the cell is in that cell range
DataValidationConstraint constraint = dataValidation.getValidationConstraint();
if (constraint.getValidationType() == DataValidationConstraint.ValidationType.LIST) { // if it is a list constraint
String[] explicitListValues = constraint.getExplicitListValues(); // if we have a explicit list like "item1, item2, item3, ..."
if (explicitListValues != null) return explicitListValues; // then return this
String formula1 = constraint.getFormula1(); // else if we have a formula creating the list
System.out.println(formula1);
Workbook workbook = sheet.getWorkbook();
AreaReference areaReference = null;
try { // is formula1 a area reference?
areaReference = new AreaReference(formula1,
(workbook instanceof XSSFWorkbook)?SpreadsheetVersion.EXCEL2007:SpreadsheetVersion.EXCEL97
);
String[] listValues = getDataFromAreaReference(areaReference, sheet); //get data from that area reference
return listValues; // and return this
} catch (Exception ex) {
//ex.printStackTrace();
// do nothing as creating AreaReference had failed
}
List<? extends Name> names = workbook.getNames(formula1); // is formula1 a reference to a defined name in Excel?
for (Name name : names) {
String refersToFormula = name.getRefersToFormula(); // get the Excel cell range the name refers to
areaReference = new AreaReference(refersToFormula,
(workbook instanceof XSSFWorkbook)?SpreadsheetVersion.EXCEL2007:SpreadsheetVersion.EXCEL97
);
String[] listValues = getDataFromAreaReference(areaReference, sheet); //get data from that area reference
return listValues; // and return this
}
}
}
}
}
return new String[]{}; // per default return an empy array
}
public static void main(String[] args) throws Exception {
//String filePath = "ExcelWorkbook.xls";
String filePath = "ExcelWorkbook.xlsx";
Workbook workbook = WorkbookFactory.create(new FileInputStream(filePath));
Sheet sheet = workbook.getSheetAt(0);
Row row = sheet.getRow(0); if (row == null) row = sheet.createRow(0); // row 1
Cell cell = row.getCell(3); if (cell == null) cell = row.createCell(3); // cell D1
System.out.println(cell.getAddress() + ":" + cell);
String[] dataValidationListValues = getDataValidationListValues(sheet, cell);
for (String dataValidationListValue : dataValidationListValues) {
System.out.println(dataValidationListValue);
}
workbook.close();
}
}
Note: Current Excel versions allow data validation list reference to be a direct area reference to another sheet without using a named range. But this is nothing what apache poi can get. Apache poi is on Excel 2007 level only.
The my_list your mean is Define Name in excel, honestly i don't know is apache-poi can do it or not. But this is may a clue, you can get the my_list formula using .getRefersToFormula();, please try the bellow code :
String defineNameFromExcel = "my_list";
List define = new ArrayList<>();
define = myExcel.getAllNames();
Iterator<List> definedNameIter = define.iterator();
while(definedNameIter.hasNext()) {
Name name = (Name) definedNameIter.next();
if(name.getNameName().equals(defineNameFromExcel)) {
String sheetName = name.getSheetName();
String range = name.getRefersToFormula();
range = range.substring(range.lastIndexOf("!"));
System.out.println(sheetName);
System.out.println(range);
}
}
It will get sheet name and range, with the information may you can extract for get the value you want, hope this helps.
Reference
I have to check if certain columns header names are present in an excel sheet in a particular order. The names are : First Name, Last Name(optional), Email Id, Phone No, Address(optional).
I need to check if I the input excel sheet has the mandatory columns as well as any combination of the optional ones.
Ex: First Name, Email Id, Phone No. (All mandatory ones)
First Name, Last Name, Email Id, Phone
A total of 4 cases are possible.
I have stored the column headers in an arraylist. (If there is an efficient way for my problem statement please let me know!).
public void readAndUpload() throws FileNotFoundException, IOException
{
FileInputStream file = new FileInputStream(new File("path.."));
HSSFWorkbook workbook = new HSSFWorkbook(file);
HSSFSheet sheet = workbook.getSheetAt(0);
HSSFRow row = sheet.getRow(0);
Iterator<Cell> cellIterator = row.cellIterator();
ArrayList<String> headerCell = new ArrayList<String>(5);
while(cellIterator.hasNext())
{
Cell cell = cellIterator.next();
headerCell.add(cell.getStringCellValue());
}
ArrayList<String> validHeaders = new ArrayList<>(Arrays.asList("First Name", "Email Id","Phone Number"));
if(headerCell.contains(validHeaders))
{
//validation logic here
}
else
{
System.out.println("Mandatory fields not present");
}
file.close();
}
What I understood from your requirement is that you would like to validate the following things,
1. If the headers in the excel are permitted headers (mandatory and optional).
2. If the mandatory headers are present.
3. If the mandatory headers are in order.
Here is one solution.
public class HeaderProblem {
public static void main(String[] args) {
List<String> headersFromExcel = Arrays.asList("EMail", "Phone", "Address", "Last Name", "First Name");
System.out.println(validate(headersFromExcel));
}
private static boolean validate(List<String> headers) {
List<String> mandatoryHeaders = Arrays.asList("First Name", "EMail", "Phone");
List<String> optionalHeaders = Arrays.asList("Last Name", "Address");
List<String> allHeaders = new ArrayList<>(mandatoryHeaders);
allHeaders.addAll(optionalHeaders);
Map<String, Integer> headerIndexMap = IntStream.range(0, headers.size())
.boxed()
.collect(Collectors.toMap(i -> headers.get(i), i -> i));
if(!allHeaders.containsAll(headers)) {
System.out.println("Some headers exist which are not allowed");
return false;
}
if (!headers.containsAll(mandatoryHeaders)) {
System.out.println("Mandatory headers are not present");
return false;
}
System.out.println(mandatoryHeaders.stream()
.map(headerIndexMap::get)
.collect(Collectors.toList()));
// Check if the manadatory headers are in order
Integer result = mandatoryHeaders.stream()
.map(headerIndexMap::get)
.reduce(-1, (x, hi) -> x < hi ? hi : headers.size());
if (result == headers.size()) {
System.out.println("Mandatory headers are not in order");
return false;
}
return true;
}
}
Here, I have assumed that the headersFromExcel field is the list of headers extracted from your excel.
One more thing, in your code you have used,
if(headerCell.contains(validHeaders))
Here, you should use containsAll() instead of contains(), because contains will consider the passed argument as one object and will compare with every individual cell of the ArrayList and will return always false in your case.
I have a big DTO with exactly 234 fields, and I have to display values of each fields of this DTO in a column of an Excel file created with apache-poi.
This is my code :
// Blank workbook
XSSFWorkbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Export values");
// Get the Entity
Simfoot simEntity = simService.findById(simId).get();
Row row = sheet.createRow(0);
row.createCell(1).setCellValue("Consult our values");
// and after this I want to convert my Simfoot object to a column in the third column ( so creteCell(2) ..... ).
I want to have in my first column : nothing , in my second only the String display ( "Consult our values" ) and in my third column I need to have my 234 fields. With an field ( the value of the field ) in one cell. So, 234 rows displaying one value in the third column.
I hope that it is clear.
Thanks a lot for your help.
Using some reflection:
// Blank workbook
XSSFWorkbook workbook = new XSSFWorkbook();
final Sheet sheet = workbook.createSheet("Export values");
// Get the Entity
final Simfoot simEntity = simService.findById(simId).get();
Row row = sheet.createRow(0);
row.createCell(1).setCellValue("Consult our values");
// and after this I want to convert my Simfoot object to a column in the third column ( so creteCell(2) ..... ).
Arrays.stream(simEntity.getClass().getDeclaredMethods())
.filter(m -> m.getName().startsWith("get") && m.getParameterTypes().length == 0 && !void.class.equals(m.getReturnType()))
.forEach(m -> {
try {
Object value = m.invoke(simEntity, null);
Row r = sheet.createRow(sheet.getLastRowNum()+1);
r.createCell(2).setCellValue(value == null ? "" : value.toString());
}
catch (Exception ex) {
// Manage Exception....
}
});
I'll add a method on Simfoot to return all the values:
public List<String> getAllValues() {
return Arrays.asList(getAtt1(), getAtt2(), .. , getAtt234());
}
Then create a row per attribute, and then you can merge the rows of the first 2 columns. Example here with 6 attributes:
int n = 6; // would be 234 for you
XSSFCellStyle styleAlignTop = workbook.createCellStyle();
styleAlignTop.setVerticalAlignment(VerticalAlignment.TOP);
Row row;
for(int i=0; i<n; i++) {
row = sheet.createRow(i);
if(i==0) {
Cell cell = row.createCell(1);
cell.setCellStyle(styleAlignTop);
cell.setCellValue("Consult our values");
}
row.createCell(2).setCellValue(simEntity.getAllValues().get(i));
}
sheet.addMergedRegion(new CellRangeAddress(0, n-1, 0, 0));
sheet.addMergedRegion(new CellRangeAddress(0, n-1, 1, 1));
It shows like this:
Another way to list your attributes would be to use Reflection but I find it very clunky:
Simfoot simEntity = new Simfoot("pap", "pep", "pip", "pop", "pup", "pyp");
for(PropertyDescriptor propertyDescriptor :
Introspector.getBeanInfo(Simfoot.class).getPropertyDescriptors()) {
System.out.println(propertyDescriptor.getReadMethod().invoke(simEntity));
}
Outputs:
pap
pep
pip
pop
pup
pyp
class Simfoot
so you have to filter out getClass and any other unwanted methods and getters
Tried Importing Excel Data to Mongo db in the Following Document Format
[
{"productId":"",
"programeName":"",
"programeThumbImageURL":"",
"programeURL":"",
"programEditors":["editor1","editor2"],
"programChapters":[
{
"chapterName":"chapter1",
"authorNames":["authorName1","authorname2"]
},
{"chapterName":"chapter2"},
"authorNames":["authorName1","authorName2"]
}
,...
]},...]
There are many products in the Excel with with chapterNames has multiple authors. following is the code which tried executing and i could do inserting data. But the i couldn't merge the authorNames corresponding to a particular chapterName as above. So currently there are programChapters array contains objects as duplicated chapterNames. Following code shows my experiment towards this.
private static XSSFWorkbook myWorkBook;
public static void main(String[] args) throws IOException {
String[] programs = {"programName1","programName2","programName3","programName4",...};
#SuppressWarnings("deprecation")
Mongo mongo = new Mongo("localhost", 27017);
#SuppressWarnings("deprecation")
DB db = mongo.getDB("dbName");
DBCollection collection = db.getCollection("programsCollection");
File myFile =
new File("dsm_article_author_details.xlsx");
FileInputStream fis = new FileInputStream(myFile); // Finds the workbook instance for XLSX file
myWorkBook = new XSSFWorkbook(fis);
XSSFSheet mySheet = myWorkBook.getSheetAt(0); // Get iterator to all the rows in current sheet
#SuppressWarnings("unused")
Iterator<Row> rowIterator = mySheet.iterator(); // Traversing over each row of XLSX file
for (String program : programs) {
String programName = "";
String chapterName = "";
String authorName = "";
BasicDBObject product = new BasicDBObject();
BasicDBList programChaptersList = new BasicDBList();
// For Each Row , Create Chapters Object here
for (int i = 0; i <= mySheet.getLastRowNum(); i++) { // points to the starting of excel i.e
// excel first row
Row row = (Row) mySheet.getRow(i); // sheet number
System.out.println("Row is :" + row.getRowNum());
BasicDBObject programChapters = new BasicDBObject();
if (row.getCell(0).getCellType() == Cell.CELL_TYPE_STRING) {
programName = row.getCell(0).getStringCellValue();
System.out.println("programName : " + programName);
}
if (row.getCell(1).getCellType() == Cell.CELL_TYPE_STRING) {
chapterName = row.getCell(1).getStringCellValue().replaceAll("\n", "");
System.out.println("chapterName : " + chapterName);
}
if (row.getCell(2).getCellType() == Cell.CELL_TYPE_STRING) {
authorName = row.getCell(2).getStringCellValue();
System.out.println("authorName : " + authorName);
}
List<String> authors = new ArrayList<String>();
programChapters.put("chapterName", chapterName);
authors.add(authorName);
programChapters.put("authorName", authors);
if (programName.trim().equals(program.trim())) {
programChaptersList.add(programChapters);
}
}
product.put("programName", program);
product.put("programThumbImageURL", "");
product.put("programeURL", "");
product.put("programChapters", programChaptersList);
collection.insert(product);
System.out.println("*#*#*#*#*#");
}
}
I hope this is the part went wrong. Need to store all chapterNames in an array and compare with each upcoming value and according to that create new objects and store it in a list
List<String> authors = new ArrayList<String>();
programChapters.put("chapterName", chapterName);
authors.add(authorName);
programChapters.put("authorName", authors);
Can someone suggest me, available solutions :-)
I hope this is the part went wrong. Need to store all chapterNames in an array and compare with each upcoming value and according to that create new objects and store it in a list
List<String> authors = new ArrayList<String>();
programChapters.put("chapterName", chapterName);
authors.add(authorName);
programChapters.put("authorName", authors);
I am trying to get the column values for a specific row in a excel using poi methods.
I am able to get the values but the problem is I want the values only from second column.
public static ArrayList<String> GetBusinessComponentList() throws IOException{
String Tcname = "TC02_AggregateAutoByPassRO_CT";
ArrayList<String> arrayListBusinessFlow ;
arrayListBusinessFlow = new ArrayList<String>();
FileInputStream fileInput = new FileInputStream(oFile);
wb = new HSSFWorkbook(fileInput);
sheet = wb.getSheet("Business Flow");
int rownr = findRow(sheet, Tcname);
row = sheet.getRow(rownr);
for (Cell cell : row) {
String arr = cell.getStringCellValue();
arrayListBusinessFlow.add(arr);
}
return arrayListBusinessFlow;
}
private static int findRow(HSSFSheet sheet, String cellContent){
for (Row row : sheet) {
for (Cell cell : row) {
if (cell.getCellType() == Cell.CELL_TYPE_STRING) {
if (cell.getRichStringCellValue().getString().trim().equals(cellContent)) {
return row.getRowNum();
}
}
}
}
return 0;
}
}
OUTPUT:
[TC02_AggregateAutoByPassRO_CT,
StrategicUINewBusiness.Login,
StrategicUINewBusiness.CustomerSearch,
StrategicUINewBusiness.NamedInsured,
StrategicUINewBusiness.InsuranceScoreByPass,
StrategicUINewBusiness.VehiclePage,
StrategicUINewBusiness.DriverPage,
StrategicUINewBusiness.ViolationPage,
StrategicUINewBusiness.UnderwritingPage,
StrategicUINewBusiness.CoveragePage,
StrategicUINewBusiness.Portfolio,
StrategicUINewBusiness.BillingPage,
StrategicUINewBusiness.FinalSalePage,
StrategicUINewBusiness.PolicyConfirmation, , , ]
But I do not want my test case name when I am getting.
Please help me what changes i needed to do. thanks!
Currently, the code you're using to iterate over cells only returns cells with content or styling, and skips totally empty ones. You need to change to one of the other ways of iterating over cells, so you can control it to read from the second column onwards.
If you look at the Apache POI Documentation on iterating over rows and cells, you'll see a lot more details on the two main ways to iterate.
For your case, you'll want something like:
// We want to read from the 2nd column onwards, zero based
int firstColumn = 1;
// Always fetch at least 4 columns
int MY_MINIMUM_COLUMN_COUNT = 5;
// Work out the last column to go to
int lastColumn = Math.max(r.getLastCellNum(), MY_MINIMUM_COLUMN_COUNT);
// To format cells into strings
DataFormatter df = new DataFormatter();
// Iterate over the cells
for (int cn = firstColumn; cn < lastColumn; cn++) {
Cell c = r.getCell(cn, Row.RETURN_BLANK_AS_NULL);
if (c == null) {
// The spreadsheet is empty in this cell
} else {
// Do something useful with the cell's contents
// eg get the cells value as a string
String cellAsString = df.formatCellValue(c);
}
}
Use Cell cell=row.getCell(1); and also you can use sheet.getLastRowNum() to get the number last row on the sheet.
for (int i=0;i<=row.getLastCellNum();i++) {
if (i!=1){
//your stuff
}
}