Repaired Records : Cell information from worksheet created - java

I'm receiving an error when opening my OpenXML created spreadsheet. The error is as follows.
repaired record : xl/worksheets/sheet.xml partial cell information
private void SavexlsExcelFile(String fullPathName)
{
using (SpreadsheetDocument document = SpreadsheetDocument.Create(fullPathName, SpreadsheetDocumentType.Workbook))
{
WorkbookPart workbookPart = document.AddWorkbookPart();
workbookPart.Workbook = new Workbook();
worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new Worksheet();
Columns columns = new Columns();
worksheetPart.Worksheet.AppendChild(columns);
Sheets sheets = workbookPart.Workbook.AppendChild(new Sheets());
Sheet sheet = new Sheet() { Id = workbookPart.GetIdOfPart(worksheetPart), SheetId = 1, Name = "Sheet" };
sheets.Append(sheet);
workbookPart.Workbook.Save();
sheetData = worksheetPart.Worksheet.AppendChild(new SheetData());
List<List<string>> dataRow = new List<List<string>>();
List<String> dtRow = new List<String>();
Row row = new Row();
for (int i = 0; i < dataGridView1.RowCount; i++)
{
for (int j = 0; j < dataGridView1.ColumnCount; j++)
{
if (i == 0)
{
Cell dataCell = new Cell();
dataCell.DataType = CellValues.String;
CellValue cellValue = new CellValue();
cellValue.Text = dataGridView1.Columns[j].Name;
dataCell.StyleIndex = 2;
dataCell.Append(cellValue);
row.AppendChild(dataCell);
//dataColumn.Add(dataGridView1.Columns[j].Name);
}
dtRow.Add(dataGridView1.Rows[i].Cells[j].Value.ToString());
}
}
dataRow.Add(dtRow);
sheetData.AppendChild(row);
row = new Row();
foreach (List<string> datarow in dataRow)
{
row = new Row();
foreach(string dtrow in datarow)
{
row.Append(ConstructCell(dtrow, CellValues.String, 2));
}
sheetData.AppendChild(row);
}
worksheetPart.Worksheet.Save();
}
}
private Cell ConstructCell(string value, CellValues dataType, uint styleIndex = 0)
{
return new Cell()
{
CellValue = new CellValue(value),
DataType = new EnumValue<CellValues>(dataType),
StyleIndex = styleIndex
};
}

There are 2 issues here that I can see. The first is that your use of Columns is incorrect. You should use Columns if you wish to control things such as the width of a column. To use Columns correctly, you'll need to add child Column elements. For example (taken from here):
Columns columns = new Columns();
columns.Append(new Column() { Min = 1, Max = 3, Width = 20, CustomWidth = true });
columns.Append(new Column() { Min = 4, Max = 4, Width = 30, CustomWidth = true });
In your sample you could just remove the following two lines
Columns columns = new Columns();
worksheetPart.Worksheet.AppendChild(columns);
The second issue is the StyleIndex you are using; the style doesn't exist in your document because you haven't added it. The easiest thing to do here is to just remove the StyleIndex altogether.
When debugging files like this, it's always worth looking at the OpenXml Productivity Tool. You can open a generated file in the tool and validate it to see what errors you have in your file.

All the text in Excel is stored under a shared string table. You need to insert the string in shared string table:
string text = dataGridView1.Columns[j].Name;
cell.DataType = CellValues.SharedString;
if (!_spreadSheet.WorkbookPart.GetPartsOfType<SharedStringTablePart>().Any())
{
_spreadSheet.WorkbookPart.AddNewPart<SharedStringTablePart>();
}
var sharedStringTablePart = _spreadSheet.WorkbookPart.GetPartsOfType<SharedStringTablePart>().First();
if (sharedStringTablePart.SharedStringTable == null)
{
sharedStringTablePart.SharedStringTable = new SharedStringTable();
}
//Iterate through shared string table to check if the value is already present.
foreach (SharedStringItem ssItem in sharedStringTablePart.SharedStringTable.Elements<SharedStringItem>())
{
if (ssItem.InnerText == text)
{
cell.CellValue = new CellValue(ssItem.ElementsBefore().Count().ToString());
SaveChanges();
return;
}
}
// The text does not exist in the part. Create the SharedStringItem.
var item = sharedStringTablePart.SharedStringTable.AppendChild(new SharedStringItem(new Text(text)));
cell.CellValue = new CellValue(item.ElementsBefore().Count().ToString());

Related

reading values form excel with single row with multiple columns

How about reading the row with multiple values using excel
for instance
reference
testcase1
testcase2
testcase3
Name
Sam
ram
cam
Age
20
25
30
sex
m
F
m
place
place1
place2
place 3
I have to read
testcase1.name=sam
testcase2.name=ram
testcase3.name=cam
and age
how can I do this... any help would be appreciated
Use apache poi library.
First you must read the Excel file in a java object
FileInputStream myFile = new FileInputStream(new File(FILE_NAME));
Workbook myWorkbook = new XSSFWorkbook(myFile);
Sheet datatypeSheet = myWorkbook.getSheetAt(0); //read the first sheet
Iterator<Row> iterator = datatypeSheet.iterator();
Then you can iterate over each row and in each row you can read each cell (aka column value)
List<TestCase> myList = new ArrayList();
int rowNum = 0;
while (iterator.hasNext()) {
Row row = iterator.next();
int columnsSize = row.getLastCellNum();
//create all objects
if(rowNum == 0) {
for (int i = 1; i <= columnsSize; i++) {
myList.add(new TestCase());
}
} else {
//initialize property in each row for all objects
for (int i = 1; i <= columnsSize; i++) {
TestCase testCase = myList.get(i-1);
int cellType = row.getCell(i).getCellType();
switch(cellType) {
case Cell.CELL_TYPE_NUMERIC:
testCase.properties.add(new Property(row.getCell(0).getStringCellValue(),
String.valueOf(row.getCell(i).getNumericCellValue()));
break;
case Cell.CELL_TYPE_STRING:
testCase.properties.add(new Property(row.getCell(0).getStringCellValue(),
row.getCell(i).getStringCellValue());
break;
}
}
}
rowNum++;
}
System.out.println(myList);
public class TestCase {
public List<Property> properties;
public TestCase(){
this.properties = new ArrayList();
}
}
public class Property {
String name;
String value;
public Property(String name, String value){
this.name = name;
this.value = value;
}
}
*Edit: For loop must have <= condition instead of <
This tutorial might be helpful to use: https://www.javatpoint.com/how-to-read-excel-file-in-java.
Basically, you are using the Apache POI Library to parse the file's values, generating iterators for each row, then for each cell in each row, and dealing with the data that way.
In your case, after importing the relevant Classes, the code snippet will be something like this:
//Input Data for Class
FileInputStream in = new FileInputStream(new File("<File Location>.xls(x)"));
// Create an Apache POI Workbook reading the file
HSSFWorkbook workbook = new HSSFWorkbook(in);
// Use the Workbook to make a sheet
HSSFSheet sheet = workbook.getSheetAt(0); // Replace 0 with your sheet number
List<Row> rowsList = new ArrayList<Row>();
sheet.iterator().forEachRemaining(actualList::add); // Gets a list of all the rows
int i = -1;
String[] names = new String[3];
for (Cell cell : rowsList[1]) { // Start at second row
if (i++ > 0) {
names[i] = cell.getStringCellValue();
}
}
testcase1.name = names[0];
testcase2.name = names[1];
testcase3.name = names[2];
i = -1;
int[] ages = new int[3];
for (Cell cell : rowsList[2]) { // Start at Third Row
if (i++ > 0) {
ages[i] = (int) cell.getNumericCellValue();
}
}
testcase1.name = ages[0];
testcase2.name = ages[1];
testcase3.name = ages[2];

How can i copy data from cells of one excel file to another excel file(in desired row and columns) in java using Apache POI

Here is the code below to fetch data from one sheet. Now my query is how can i store this all output data, so that i can write another method to paste it in a diffrent sheet.
public void ReadCount(String Path) {
String []module;
int [][]status;
try {
FileInputStream fs = new FileInputStream(new File(Path));
XSSFWorkbook workBook = new XSSFWorkbook(fs);
boolean isPresent = false;
XSSFSheet sheet = workBook.getSheetAt(0);
for (int i=0; i<sheet.getLastRowNum(); i++) {
Row r = sheet.getRow(i);
for (int cn=0; cn<r.getLastCellNum(); cn++) {
Cell c = r.getCell(cn);
c.setCellType ( Cell.CELL_TYPE_STRING );
String text = c.getStringCellValue();
if(text.trim().equalsIgnoreCase("Module Name")) {
for(int a = i+2; a<sheet.getLastRowNum(); a++) {
Row p = sheet.getRow(a);
Cell q = p.getCell(cn);
q.setCellType ( Cell.CELL_TYPE_STRING );
String m = q.getStringCellValue();
System.out.println(m);
Cell k = p.getCell(cn+1);
k.setCellType ( Cell.CELL_TYPE_NUMERIC );
double PASS = k.getNumericCellValue();
int P = (int)PASS;
System.out.println(P);
Cell l = p.getCell(cn+2);
l.setCellType ( Cell.CELL_TYPE_NUMERIC );
double FAIL = l.getNumericCellValue();
int F = (int)FAIL;
System.out.println(F);
Cell n = p.getCell(cn+3);
n.setCellType ( Cell.CELL_TYPE_NUMERIC );
double ONHOLD = n.getNumericCellValue();
int O = (int)ONHOLD;
System.out.println(O);
}
//return module;
}
}
}
} catch(IOException e) {
e.printStackTrace();
}
}
The console output for this method is
ROW1
1
0
0
ROW2
1
0
0
ROW3
0
1
0
ROW4
0
1
1

Apache POI and Auto Row Height with merged cells

I'm using Apache POI and I am running into a weird problem. I can auto-size my rows, but only if there are no merged cells in that row. Here's an example:
new FileOutputStream('test.xlsx').withStream { OutputStream os ->
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet();
CellStyle wrapStyle = workbook.createCellStyle();
wrapStyle.setWrapText(true);
Row row = sheet.createRow(0); row.setRowStyle(wrapStyle);
Cell cell = row.createCell(0); cell.setCellStyle(wrapStyle);
cell.setCellValue("Very long text that needs to be wrapped")
cell = row.createCell(1); cell.setCellStyle(wrapStyle);
cell.setCellValue("Short text");
cell = row.createCell(2); cell.setCellStyle(wrapStyle);
cell.setCellValue("");
// These two lines break row auto-height!
//
CellRangeAddress cellRangeAddress = new CellRangeAddress(0, 0, 1, 2);
sheet.addMergedRegion(cellRangeAddress);
workbook.write(os);
}
This code generates the following document:
However, as soon as I comment out the lines that merge the two cells, the output looks like this:
Is this a bug? Does anyone know of a workaround?
By using the last part from Val Blant I've did something that's easier to use, and yet much complex.
Please be aware that there is a single line of code that adds one additional line to the cell height-wise, for personal reasons. If you do not wish that, please remove it. Also feel free to change it to a non-static, I've had to use static methods due to the company I'm working for making the specific class static.
PS: It's my first post on stackoverflow, please be gentle. :)
Solution:
public static Boolean isCellMerged(Cell cell) {
Sheet sheet = cell.getSheet();
for (CellRangeAddress mergedRegionRange : sheet.getMergedRegions()) {
Integer cellColumn = cell.getColumnIndex();
Integer cellRow = cell.getRowIndex();
if (mergedRegionRange.containsColumn(cellColumn) && mergedRegionRange.containsRow(cellRow)) {
return true;
}
}
return false;
}
public static List<List<Cell>> getCellsInRowsInsideRegionRange(Cell cell) {
Sheet sheet = cell.getSheet();
List<List<Cell>> mergedRowList = new ArrayList<>();
List<Cell> mergedCellsList = new ArrayList<>();
//Nejdříve musíme zjistit sloučenou sekci dané buňky
for (CellRangeAddress mergedRegionRange : sheet.getMergedRegions()) {
Integer cellColumn = cell.getColumnIndex();
Integer cellRow = cell.getRowIndex();
if (mergedRegionRange.containsColumn(cellColumn) && mergedRegionRange.containsRow(cellRow)) {
//Protože CellRangeAddress nemá moc metod, musíme si pomoci sami a získat z ní buňky a řádky
for (Row row : sheet) {
for (Cell iteratedCell : row) {
Integer iteratedCellColumn = iteratedCell.getColumnIndex();
Integer iteratedCellRow = iteratedCell.getRowIndex();
if (mergedRegionRange.containsColumn(iteratedCellColumn) && mergedRegionRange.containsRow(iteratedCellRow)) {
//Rozdělování jednotlivých řádků
//Není-li řádek bez buněk...
if (!mergedCellsList.isEmpty()) {
//Tak buňku přidáme do Listu buněk...
mergedCellsList.add(iteratedCell);
} else {
//Pokud se jedná o první buňku prvního řádku, tak přidáme rovnou
mergedCellsList.add(iteratedCell);
}
}
}
//Vložíme List buněk daného řádku do Listu řádků
if (!mergedCellsList.isEmpty()) {
mergedRowList.add(mergedCellsList);
}
//A vyresetujeme list buněk (začneme tak nanovo novým řádkem)
mergedCellsList = null;
mergedCellsList = new ArrayList<>();
}
//Vrátíme výsledný List řádků, obsahující Listy buněk ve sloučené sekci.
if (!mergedRowList.isEmpty()) {
return mergedRowList;
} else {
return null;
}
}
}
return null;
}
public static void adjustRowHeightForRowWithNonMergedCells(Row row) {
row.setHeight((short) -1);
}
public static void adjustRowHeightForRowWithMergedCells(Row row) {
Sheet sheet = row.getSheet();
Cell longestTextCell = null;
//Potřebujeme získat buňku s nejdelším textem
for (Cell iteratedCell : row) {
String iteratedTextString = iteratedCell.getStringCellValue();
if (longestTextCell != null && StringUtils.isNotBlank(longestTextCell.getStringCellValue())) {
if (iteratedTextString.length() > longestTextCell.getStringCellValue().length()) {
longestTextCell = iteratedCell;
}
} else {
longestTextCell = iteratedCell;
}
}
//Z textově nejobsáhlejší buňky potřebujeme dostat údaje
String longestText = "";
if (StringUtils.isNotBlank(longestTextCell.getStringCellValue()) && longestTextCell != null) {
longestText = longestTextCell.getStringCellValue();
//Protože textově nejobsáhlejší buňka nemusí nutně být sloučeného typu, je zapotřebí to všude ošetřit
Boolean isLongestTextCellMerged = isCellMerged(longestTextCell);
Float longestCellWidthInPixels = 0f;
Float longestMergedCellWidthInPixels = 0f;
//Získat šířku nesloučené nejobsáhlejší buňky je jednoduché
if (!isLongestTextCellMerged) {
Integer longestCellColumnIndex = longestTextCell.getColumnIndex();
longestCellWidthInPixels = sheet.getColumnWidthInPixels(longestCellColumnIndex);
} else {
//Musíme přijít na šířku sloučené buňky namísto buňky uvnitř sloučené buňky
List<List<Cell>> cellsInMergedRegion = getCellsInRowsInsideRegionRange(longestTextCell);
longestMergedCellWidthInPixels = 0f;
//Projdeme řádky
for (List<Cell> iteratedCell2List : cellsInMergedRegion) {
Float iteratedMergedCell2WidthInPixels = 0f;
//Projdeme jednotlivé buňky ve sloučené buňce na řádku a sečteme jejich šířky
for (Cell iteratedCell2 : iteratedCell2List) {
Integer iteratedCell2ColumnIndex = iteratedCell2.getColumnIndex();
Float iteratedCell2ColumnWidthInPixels = sheet.getColumnWidthInPixels(iteratedCell2ColumnIndex);
iteratedMergedCell2WidthInPixels = iteratedMergedCell2WidthInPixels + iteratedCell2ColumnWidthInPixels;
}
//Získáme šířku nejširší sloučené buňky na řádku
if (iteratedMergedCell2WidthInPixels > longestMergedCellWidthInPixels) {
longestMergedCellWidthInPixels = iteratedMergedCell2WidthInPixels;
}
//Resetujeme sčítání
iteratedMergedCell2WidthInPixels = 0f;
}
}
//Uložíme si nejširší buňku dle toho, zda je sloučená či nikoliv
Float longestWidthInPixels;
if (isLongestTextCellMerged) {
longestWidthInPixels = longestMergedCellWidthInPixels;
} else {
longestWidthInPixels = longestCellWidthInPixels;
}
//Potřebujeme font
Workbook wb = sheet.getWorkbook();
Short fontIndex = longestTextCell.getCellStyle().getFontIndex();
Font excelFont = wb.getFontAt(fontIndex);
//Potřebujeme i jeho styl
Integer excelFontStyle = java.awt.Font.PLAIN;
if (excelFont.getBold()) excelFontStyle = java.awt.Font.BOLD;
if (excelFont.getItalic()) excelFontStyle = java.awt.Font.ITALIC;
//Potřebujeme získat skutečný font i s velikostí
java.awt.Font currentFont = new java.awt.Font(excelFont.getFontName(), excelFontStyle, excelFont.getFontHeightInPoints());
//Získáme řetězec s vlastností
AttributedString attributedString = new AttributedString(longestText);
attributedString.addAttribute(TextAttribute.FONT, currentFont);
//Použijeme LineBreakMeasurer k zjištění kolik řádků bude text potřebovat
FontRenderContext fontRenderContext = new FontRenderContext(null, true, true);
LineBreakMeasurer measurer = new LineBreakMeasurer(attributedString.getIterator(), fontRenderContext);
Integer nextPosition = 0;
Integer lineCount = 0;
while (measurer.getPosition() < longestText.length()) {
nextPosition = measurer.nextOffset(longestWidthInPixels);
//Také musíme ošetřit případ manuálně zadaných LineBreaků pro všechny možné techtle mechtle :-S
String textLine = StringUtils.substring(longestText, measurer.getPosition(), nextPosition);
Boolean containsNewLine = StringUtils.containsIgnoreCase(textLine, "\r") || StringUtils.containsIgnoreCase(textLine, "\\r") || StringUtils.containsIgnoreCase(textLine, "\n") || StringUtils.containsIgnoreCase(textLine, "\\n");
if (containsNewLine) {
if (StringUtils.containsIgnoreCase(textLine, "\r\n") || StringUtils.containsIgnoreCase(textLine, "\\r\\n")) {
lineCount = lineCount + StringUtils.countMatches(textLine, "\n");
} else {
if (StringUtils.containsIgnoreCase(textLine, "\r") || StringUtils.containsIgnoreCase(textLine, "\\r")) {
lineCount = lineCount + StringUtils.countMatches(textLine, "\r");
}
if (StringUtils.containsIgnoreCase(textLine, "\n") || StringUtils.containsIgnoreCase(textLine, "\\n")) {
lineCount = lineCount + StringUtils.countMatches(textLine, "\n");
}
}
lineCount = lineCount + StringUtils.countMatches(textLine, "\\r?\\n");
}
lineCount++;
measurer.setPosition(nextPosition);
}
//Máme počet řádků, zbývá konečný dopočet výšky řádku a jeho použití
if (lineCount > 1) {
Float fontHeight = currentFont.getLineMetrics(longestText, fontRenderContext).getHeight();
//Pro jistotu přidáme jeden řádek navíc, člověk nikdy neví...
lineCount = lineCount + 1;
//Potřebujeme získat poslední řádek
Row lastRow = null;
if (isCellMerged(longestTextCell)) {
List<List<Cell>> mergedCellsInRows = getCellsInRowsInsideRegionRange(longestTextCell);
Integer lastRowInMergedSectionIndex = mergedCellsInRows.size() - 1;
List<Cell> lastRowInMergedSection = mergedCellsInRows.get(lastRowInMergedSectionIndex);
lastRow = lastRowInMergedSection.get(0).getRow();
} else {
lastRow = longestTextCell.getRow();
}
//Je potřeba ošetřit velikosti, pokud má sloučená buňka vícero řádků
Float cellsMergedAboveHeight = 0f;
if (isCellMerged(longestTextCell)) {
if (getCellsInRowsInsideRegionRange(longestTextCell).size() > 1) {
List<List<Cell>> mergedCellsInRows = getCellsInRowsInsideRegionRange(longestTextCell);
for (List<Cell> rowsWithCells : mergedCellsInRows){
if (!lastRow.equals(rowsWithCells.get(0).getRow())){
cellsMergedAboveHeight = cellsMergedAboveHeight + rowsWithCells.get(0).getRow().getHeight();
}
}
}
}
//Vzorec je ((Velikost fontu krát počet řádků plus (počet řádků krát volný prostor mezi řádky)) krát přepočet Excelu) mínus výška sloučených buněk nad posledním řádkem.
Short finalRowHeight = (short) (((fontHeight * lineCount + (lineCount * 15))* 10) - cellsMergedAboveHeight);
//A výsledek nastavíme na poslední řádek, protože jinak to przní sloupce vlevo a vpravo od vyšších řádků
lastRow.setHeight(finalRowHeight);
}
}
}
I was having a similar problem where row height was not adjusting for merged cells.
I had to write a custom function for adjusting height of that particular row. Here is my code:
I have fixed column width in my sheet to be 24, and default font size to be 11.
I needed adjustment in row height whenever my font size > 11 and cell text length is overflowing the column width or isn't visible properly due to larger length.
private void adjustRowHeightMergedCells(final XSSFCell mergedCell) {
DataFormatter dataFormatter = new DataFormatter();
int defaultCharWidth = SheetUtil.getDefaultCharWidth(mergedCell.getRow().getSheet().getWorkbook());
XSSFRow row = mergedCell.getRow();
// Getting merged cell width value
double cellValueWidth = SheetUtil.getCellWidth(mergedCell, defaultCharWidth, dataFormatter, true);
// If cell width value > 24 (Default value), calculate how much extra row height is needed
// This happends when text length is larger than the column width (24)
float extraRowHeightDueToCellTextLength = (float) Math.floor(cellValueWidth / 24) * row.getHeightInPoints();
float extraRowHeightDueToCellTextFontSize = 0;
// If cell font size > 11 (Default value), calculate how much extra row height is needed
short cellTextFontSize = mergedCell.getCellStyle().getFont().getFontHeightInPoints();
if (cellTextFontSize > 11) {
extraRowHeightDueToCellTextFontSize = (cellTextFontSize-ExcelConstants.DEFAULT_FONT_SIZE) * (5f/3f);
}
// 5f/3f in above calculation is custom number which assumed by thinking that for font size 11, my row height shud be 15, and for example custom font size 20, row height shud be 30, hence the factor 5f/ 3f( per extra 1 point increase in font size above 11, row height shud be increased by 5/3)
// Larger of two adjustment values will be taken and added to current row height
float extraRowHeightAdjustment = Math.max(extraRowHeightDueToCellTextFontSize,extraRowHeightDueToCellTextLength);
if(extraRowHeightAdjustment > 0) {
row.setHeightInPoints(row.getHeightInPoints() + extraRowHeightAdjustment);
}
}
Kinda hacky solution but works for my situation, you can modify it per your requirements.
After more research, turns out that this is a problem with Excel itself, not POI. Excel does indeed lose its ability to auto-fit rows to content for all rows that have merged cells in them. For more info see:
http://excel.tips.net/T003207_Automatic_Row_Height_For_Merged_Cells_with_Text_Wrap.html
http://blog.contextures.com/archives/2012/06/07/autofit-merged-cell-row-height/
The workaround is based on predicting the number of lines in the largest cell of the row, and then adjusting the row height manually. The code is based on this discussion:
http://mail-archives.apache.org/mod_mbox/poi-user/200906.mbox/%3C24216153.post#talk.nabble.com%3E
RowInfo and NestedCellInfo below are my custom data structures that keep track of the sheet layout. You should be able to replace these with your equivalents and helper functions.
private void adjustRowHeights(Sheet sheet, List<RowInfo> rows, SortedSet<Integer> createdColumnNumbers) {
SortedMap<Integer, Float> columnWidthsInPx = [] as TreeMap;
createdColumnNumbers.each {
columnWidthsInPx.put(it, sheet.getColumnWidthInPixels(it));
}
rows.each { RowInfo rowInfo ->
if ( rowInfo.hasMergedCells ) {
Row excelRow = sheet.getRow(rowInfo.rowIndex);
// Find the column with the longest text - that's the one that will determine
// the row height
//
NestedCellInfo longestCell = rowInfo.getCellWithLongestContent();
String cellText = longestCell.getText();
if ( cellText != null && cellText.size() > 5 ) {
int colIdx = rowInfo.cells.indexOf(longestCell);
// Figure out available width in pixels, taking colspans into account
//
float columnWidthInPx = columnWidthsInPx[colIdx];
int numberOfMergedColumns = longestCell.colSpan;
(numberOfMergedColumns - 1).times {
columnWidthInPx += columnWidthsInPx[colIdx + it];
}
// Setup the font we'll use for figuring out where the text will be wrapped
//
XSSFFont cellFont = longestCell.getCellFont();
int fontStyle = Font.PLAIN;
if ( cellFont.getBold() ) fontStyle = Font.BOLD;
if ( cellFont.getItalic() ) fontStyle = Font.ITALIC;
java.awt.Font currFont = new java.awt.Font(
cellFont.getFontName(),
fontStyle,
cellFont.getFontHeightInPoints());
AttributedString attrStr = new AttributedString(cellText);
attrStr.addAttribute(TextAttribute.FONT, currFont);
// Use LineBreakMeasurer to count number of lines needed for the text
//
FontRenderContext frc = new FontRenderContext(null, true, true);
LineBreakMeasurer measurer = new LineBreakMeasurer(attrStr.getIterator(), frc);
int nextPos = 0;
int lineCnt = 0;
while (measurer.getPosition() < cellText.length()) {
nextPos = measurer.nextOffset( columnWidthInPx );
lineCnt++;
measurer.setPosition(nextPos);
}
if ( lineCnt > 1 ) {
excelRow.setHeight((short)(excelRow.getHeight() * lineCnt * /* fudge factor */ 0.7));
}
}
}
}
This solution is far from perfect, but it allowed me to move forward.

XLSX excel (POI Java). No data appear on row and column

Here's my code:
try {
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename="
+ ReportID + ".xlsx");
String excelFileName = "C:\\Test.xlsx";
XSSFWorkbook w = new XSSFWorkbook();
System.out.println("w: " + w);
XSSFSheet s = w.createSheet(ReportID);
System.out.println("s: " + s);
// Report Title
s.createRow(0).createCell(0).setCellValue(Title);
System.out.println("Title: " + Title);
// Populate the worksheet
int _col_cnt = HeadersLabel.length;
XSSFRow row = s.createRow(_col_cnt);
System.out.println("HeadersLabel: " + _col_cnt);
for (int c = 0; c < _col_cnt; c++) {
// Construct the header row
String _h = HeadersLabel[c];
System.out.println("_h: " + _h);
//XSSFRow row = s.createRow(0);
if (_h != null) {
XSSFCell hd = row.createCell(c);
hd.setCellValue(_h);
}
int r = 5;
for (Iterator iter = Cells.iterator(); iter.hasNext();) {
Object[] _o = (Object[]) iter.next();
XSSFRow rowData = s.createRow(r);
XSSFCell data = rowData.createCell(c);
if (CellDataType[c].equals("STRING")
|| CellDataType[c].equals("VARCHAR")) {
String _l = (String) _o[c];
if (_l != null) {
// Label label = new Label(c, r, (String) _o[c]);
//XSSFCell data = rowData.createCell(c);
data.setCellValue(_l);
}
} else if (CellDataType[c].equals("DOUBLE")) {
Double _D = (Double) _o[c];
if (_D != null) {
// Number number = new Number(c, r,
// _D.doubleValue());
// s.addCell(number);
//XSSFCell data = rowData.createCell(c);
data.setCellValue(_D);
}
} else if (CellDataType[c].equals("INTEGER")) {
Integer _I = (Integer) _o[c];
if (_I != null) {
// Number number = new Number(c, r,
// _I.doubleValue());
// s.addCell(number);
//XSSFCell data = rowData.createCell(c);
data.setCellValue(_I);
}
} else if (CellDataType[c].equals("DATE")) {
Date _aDate = (Date) _o[c];
if (_aDate != null) {
// DateTime dateCell = new DateTime(c, r, _aDate,
// dateFormat);
// s.addCell(dateCell);
//XSSFCell data = rowData.createCell(c);
data.setCellValue(_aDate);
}
} else if (CellDataType[c].equals("TIMESTAMP")) {
Timestamp _aTimestamp = (Timestamp) _o[c];
Date _aDate = Timestamp2Date(_aTimestamp);
if (_aDate != null) {
// DateTime dateCell = new DateTime(c, r, _aDate,
// dateFormat);
// s.addCell(dateCell);
//XSSFCell data = rowData.createCell(c);
data.setCellValue(_aDate);
}
}
The XLSX excel did not manage to capture some data. The first two column is empty but there's suppose to be data appearing. Only the third column has the data.
What it looks like now: https://www.dropbox.com/s/2vfxsootyln6qq5/Capture3.JPG
What it suppose to be like: https://www.dropbox.com/s/d0yctgk4pywh140/Capture2.JPG
When you are writing the cell content, for each cell iteration, you are creating new row, which actually removing your previous row, and so at the end, you are getting data on your last cell only. Following is your code.
for (Iterator iter = Cells.iterator(); iter.hasNext();) {
Object[] _o = (Object[]) iter.next();
XSSFRow rowData = s.createRow(r);
s.createRow(0).createCell(0).setCellValue(Title);
You need to call create row just once for each row before entering in this loop. Once the row is created you just need to create column, and that must be for each column of that row It should be like following.
XSSFRow rowData = s.createRow(r);
for (Iterator iter = Cells.iterator(); iter.hasNext();) {
Object[] _o = (Object[]) iter.next();
rowData..createCell(0).setCellValue(Title);
Please note it is my first reflection on your code, and I have not tried the same on my system. So just take it as a hint and correct the same wherever required and then check again.

Create table with docx4j

I try to create a new table depending on input data and insert it into an docx-document.
Following leads to a corrupted output file:
private Tbl getSampleTable(WordprocessingMLPackage wPMLpackage) {
ObjectFactory factory = Context.getWmlObjectFactory();
int writableWidthTwips = wPMLpackage.getDocumentModel().getSections().get(0).getPageDimensions().getWritableWidthTwips();
List<Map<String, String>> data = getSampleTableData();
TableDefinition tableDef = getSampleTableDef();
int cols = tableDef.getColumns().size();
int cellWidthTwips = new Double(Math.floor((writableWidthTwips / cols))).intValue();
Tbl table = TblFactory.createTable((data.size() + 1), cols, cellWidthTwips);
Tr headerRow = (Tr) table.getContent().get(0);
int f = 0;
for (Column column : tableDef.getColumns()) {
Tc column = (Tc) headerRow.getContent().get(f);
f++;
Text text = factory.createText();
text.setValue(column.getName());
R run = factory.createR();
run.getContent().add(text);
column.getContent().add(run);
headerRow.getContent().add(column);
}
int i = 1;
for (Map<String, String> entry : data) {
Tr row = (Tr) table.getContent().get(i);
i++;
int p = 0;
for (String key : entry.keySet()) {
Tc column = (Tc) row.getContent().get(p);
p++;
Text tx = factory.createText();
R run = factory.createR();
tx.setValue(entry.get(key));
run.getContent().add(tx);
column.getContent().add(run);
row.getContent().add(column);
}
}
return table;
}
Without inserting the table the docx-document is created how it shall be.
I use the this function by trying to insert this table in an file that I receive as input parameter:
ByteArrayInputStream bis = new ByteArrayInputStream(file);
WordprocessingMLPackage wPMLpackage = null;
wPMLpackage = WordprocessingMLPackage.load(bis);
// Zip it up
ByteArrayOutputStream baos = new ByteArrayOutputStream();
SaveToZipFile saver = new SaveToZipFile(wPMLpackage);
saver.save(baos);
byte[] template = baos.toByteArray();
WordprocessingMLPackage target = WordprocessingMLPackage.load(new ByteArrayInputStream(template));
target.getMainDocumentPart().getContent().clear();
target.getMainDocumentPart().addObject(getSampleTable(target));
ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
SaveToZipFile saver2 = new SaveToZipFile(target);
saver2.save(baos2);
return baos2.toByteArray();
Someone has an idea why the generated file can't be interpreted by Microsoft Word? The error message is "The file can't be opened as its contents causes problems". Manipulation of the document works as long as I don't insert this table.
Inserting the runs in paragraphs leads to the desired result:
private Tbl getSampleTable(WordprocessingMLPackage wPMLpackage) {
ObjectFactory factory = Context.getWmlObjectFactory();
int writableWidthTwips = wPMLpackage.getDocumentModel().getSections()
.get(0).getPageDimensions()
.getWritableWidthTwips();
List<Map<String, String>> data = getSampleTableData();
TableDefinition tableDef = getSampleTableDef();
int cols = tableDef.getColumns().size();
int cellWidthTwips = new Double(
Math.floor((writableWidthTwips / cols))
).intValue();
Tbl table = TblFactory.createTable((data.size() + 1), cols, cellWidthTwips);
Tr headerRow = (Tr) table.getContent().get(0);
int f = 0;
for (Column column : tableDef.getColumns()) {
Tc column = (Tc) headerRow.getContent().get(f);
P columnPara = (P) column.getContent().get(0);
f++;
Text text = factory.createText();
text.setValue(column.getName());
R run = factory.createR();
run.getContent().add(text);
columnPara.getContent().add(run);
}
int i = 1;
for (Map<String, String> entry : data) {
Tr row = (Tr) table.getContent().get(i);
i++;
int d = 0;
for (String key : entry.keySet()) {
Tc column = (Tc) row.getContent().get(d);
P columnPara = (P) column.getContent().get(0);
d++;
Text tx = factory.createText();
R run = factory.createR();
tx.setValue(entry.get(key));
run.getContent().add(tx);
columnPara.getContent().add(run);
}
}
return table;
}
In creating a table (or anything else for that matter), one approach worth bearing in mind is to create what you want in Word, then use one of the docx4j code gen tools to generate corresponding Java code.
The code gen tool is available 2 ways:
online at http://webapp.docx4java.org/OnlineDemo/PartsList.html
or as a Word AddIn, see http://www.docx4java.org/forums/docx4jhelper-addin-f30/
The advantage of the Word AddIn is that you avoid the save-upload cycle.

Categories