Cannot detect strikeout data from excel using apache poi - java

I am using Java 8, excel and apache poi for my project. There are certain cell values that I am interested in extracting from excel using java. I am trying to detect text which is strikeout in the excel cells, but the format of text is little different that is why I am facing some problems.
Below is how data laid out in my excel sheet:
After extacting this data from excel, I always save it in string arraylist format like this a = [text 1, text 2, text 3]. code is mentioned below if you want to see how I am storing data in this arraylist.
What I want:
I want to ignore all those texts which are strikeout, so in above case I expect to have output like this [text 2, text 3] for first picture and second picture.
What I tried:
For the sake of just detecting strikeout values, I tried below code first:
XSSFRichTextString text = new XSSFRichTextString(a.get(0));
XSSFFont font = text.getFontAtIndex(0);
Boolean font_striked = font.getStrikeout();
but above code is not working as font_striked returns null, it must return true or false
The code which partially works in my case on single line cell values is:
boolean striked_out = sheet.getRow(row_index).getCell(column_index).getCellStyle().
getFont().getStrikeout();
This code only works if there is single line value in the cell and not with bullet list as shown above. It fails as it is not made for such kind of text.
P.S
I believe that if somehow I am able to detect even a single strikeout string in bullet points from arraylist, I can make it work for all the data.
As per the answer below I have updated my question adding following code to show how I make my string arraylist
How I convert data in excel into Arraylist:
String value_header = cell.getStringCellValue();
String[] newline_split = value_header.split("-");
for (int i = 0; i < newline_split.length; i++){
final_values = newline_split[i].
replace("\n"," ").replaceAll("\\s{2,}", " ").trim();
XSSFRichTextString text = new XSSFRichTextString(final_values);
XSSFFont font = text.getFontAtIndex(0);
Boolean font_striked = font.getStrikeout();
} // for ends here

You will need to get the RichTextString first, then go through all FormattingRuns, check whether it is stroked out and only if not, then get the appropriated substring and put it into the List:
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.usermodel.CellType.*;
import org.apache.poi.xssf.usermodel.*;
import java.io.FileInputStream;
import java.util.List;
import java.util.ArrayList;
class ReadExcelRichTextCells {
public static void main(String[] args) throws Exception {
Workbook wb = WorkbookFactory.create(new FileInputStream("ExcelRichTextCells.xlsx"));
Sheet sheet = wb.getSheetAt(0);
for (Row row : sheet) {
for (Cell cell : row) {
switch (cell.getCellTypeEnum()) {
case STRING:
XSSFRichTextString richtextstring = (XSSFRichTextString)cell.getRichStringCellValue();
String textstring = richtextstring.getString();
List<String> textparts = new ArrayList<String>();
if (richtextstring.hasFormatting()) {
for (int i = 0; i < richtextstring.numFormattingRuns(); i++) {
if (richtextstring.getFontOfFormattingRun(i)==null || !richtextstring.getFontOfFormattingRun(i).getStrikeout()) {
int indexofformattingrun = richtextstring.getIndexOfFormattingRun(i);
String textpart = textstring.substring(indexofformattingrun,
indexofformattingrun + richtextstring.getLengthOfFormattingRun(i));
String[] textpart_split = textpart.split("-");
for (int j = 0; j < textpart_split.length; j++){
String text = textpart_split[j].replace("\n", "").trim();
if (!"".equals(text)) textparts.add(text);
}
}
}
} else {
textparts.add(textstring);
}
System.out.println(textparts);
break;
//...
default:
System.out.println("default cell"); //should never occur
}
}
}
wb.close();
}
}

This is how to get the strikethrough in Excel with VBA:
Public Sub IsMyActivecellStriked()
Debug.Print ActiveCell.Font.Strikethrough
End Sub
If you have something like this:
Then the you should find a way to access the characters and check for them. Like this:
Option Explicit
Public Sub TestMe()
Dim strRange As String
Dim varArr As Variant
Dim varStr As Variant
Dim lngStart As Long
Dim lngEnd As Long
strRange = [a1]
varArr = Split(strRange, Chr(10))
For Each varStr In varArr
lngStart = InStr(1, strRange, varStr)
Debug.Print [a1].Characters(Start:=lngStart, Length:=Len(varStr)).Font.Strikethrough
Debug.Print [a1].Characters(Start:=lngStart, Length:=Len(varStr)).Text
Next varStr
End Sub
This will give you the following in the immediate window:
False
aaa
True
bbb
True
ccc
False
ddd
This should be possible to be translated into Java with the POI library.

As per I understanding above question Question (plz Correct me if I am wrong..!)
It should show whether your text in cell is strikethrough or not. ( TRUE or FALSE)
Below I have created a demo with that :
public class ApachePOI {
public static void main(String[] args) {
//Using workbook
XSSFWorkbook workbook;
try {
//Access excel file as workbook
workbook = new XSSFWorkbook(new FileInputStream(new File("/testExcelfile.xlsx")));
// first sheet of excel file
XSSFSheet xssfFirstSheet = workbook.getSheetAt(0);
//Check for A1 cell that strikethrough or not
boolean strikedOutTextStatus = xssfFirstSheet.getRow(0).getCell(0).getCellStyle().getFont().getStrikeout();
//print status of A1 cell text
System.out.println(strikedOutTextStatus);
// UPDATED CODE
if(strikedOutTextStatus){
String cellStringValue = xssfFirstSheet.getRow(0).getCell(0).getStringCellValue();
System.out.println("cell Value : "+cellStringValue.replace("-", "").replace(" ", ""));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

Related

Can't set type for excel cell in java

I am using org.apache.poi for excel interaction through Java and I am using SXSSF (not any other format like HSSF etc.). Here is how I want to set type.
private void setTechSheet(SXSSFWorkbook workbook, String entityJson) {
SXSSFSheet tech = workbook.createSheet("tech");
SXSSFRow jwtRow = tech.createRow(0);
SXSSFRow SecondRow = tech.createRow(1);
jwtRow.createCell(1).setCellValue(entityJson);
}
If to put this in the 4th line of method:
jwtRow.createCell(1).setCellType(CellType.STRING).setCellValue(entityJson),
it won't let me set value. As I read from tutorial, the cell will be the type of datas I write (string in my example). But when I open excel and click on my cell it still shows general type. How can I solve this problem? I want the cell to be any type, but not general.
General is not the type but the data format. So you have a cell containing a text value in General data format. That is the default. There is nothing wrong with this.
The special Text data format only is needed when one needs to store numbers as text for example.
If you need Text data format, then setting # as data format is necessary. For this, the cell needs a cell style having that data format. And because cell styles are stored on workbook level and shared between all cells having that date format, each data format needs to be created only once per workbook and then applied to all cells which shall use this data format.
SXSSFWorkbook workbook...
...
DataFormat format = workbook.createDataFormat();
CellStyle textStyle = workbook.createCellStyle();
textStyle.setDataFormat(format.getFormat("#"));
...
setTechSheet(workbook, "1234", textStyle);
...
private void setTechSheet(SXSSFWorkbook workbook, String entityJson, CellStyle textStyle) {
SXSSFSheet tech = workbook.createSheet("tech");
SXSSFRow jwtRow = tech.createRow(0);
SXSSFCell cell = jwtRow.createCell(1);
cell.setCellValue(entityJson);
cell.setCellStyle(textStyle);
}
...
Following complete example shows when data format Text is needed.
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.*;
public class SXSSFTextDataFormat {
private static void setTechSheet(SXSSFWorkbook workbook, Object[][] techSheetData, CellStyle textStyle) {
SXSSFSheet tech = workbook.createSheet("tech");
int r = 0;
for (Object[] dataRow : techSheetData) {
SXSSFRow row = tech.createRow(r);
int c = 0;
for (int i = 0; i < dataRow.length; i+=2) {
SXSSFCell cell = row.createCell(c);
Object data = dataRow[i];
String format = (String)dataRow[i+1];
if (data instanceof Number) {
cell.setCellValue(((Number)data).doubleValue());
} else {
cell.setCellValue(String.valueOf(data));
}
if ("Text".equals(format)) {
cell.setCellStyle(textStyle);
}
c++;
}
r++;
}
}
public static void main(String args[]) throws Exception {
Object[][] techSheetData = new Object[][] {
new Object[] {"A1", "General", new java.math.BigInteger("12345678901234567890"), "General"},
new Object[] {"A2", "General", "12345678901234567890", "Text"},
new Object[] {"A3", "General", "12345678901234567890", "General"},
};
try ( SXSSFWorkbook workbook = new SXSSFWorkbook();
java.io.FileOutputStream out = new java.io.FileOutputStream("./Excel.xlsx")) {
DataFormat format = workbook.createDataFormat();
CellStyle textStyle = workbook.createCellStyle();
textStyle.setDataFormat(format.getFormat("#"));
setTechSheet(workbook, techSheetData, textStyle);
workbook.write(out);
workbook.dispose();
}
}
}
The big integer in B1will not be stored in Excel properly because Excel only stores numbers in double precision.
The big integer string in B2 is formatted using Text data format. So one can edit that cell in Excel's GUI without destroying the format.
The big integer string in B3 is formatted using General data format. So if one edits that cell in Excel's GUI this will destroy the format and Excel converts the number into a double value.

Apache POI not applying certain color indices

Java 8 and Apache POI 4.1.x here. I have some Java code that writes a list of objects to an Excel file and its working perfectly fine, with the exception of some color-based cell styles I'm trying to apply:
public void applyPriceListDataCellStyle(PriceListItem priceListItem, Cell cell) {
short colorIndex;
switch(priceListItem.getChangeType()) {
case ADDITION:
colorIndex = IndexedColors.YELLOW.getIndex();
break;
case DELETION:
XSSFColor purple = new XSSFColor(new java.awt.Color(120,81,169), new DefaultIndexedColorMap());
colorIndex = purple.getIndex();
break;
case PRICE_ADJUSTMENT_INCREASE:
colorIndex = IndexedColors.RED.getIndex();
break;
case PRICE_ADJUSTMENT_DECREASE:
colorIndex = IndexedColors.GREEN.getIndex();
break;
default:
// NO_CHANGE (leave unstyled)
colorIndex = IndexedColors.WHITE.getIndex();
break;
}
Map<String,Object> cellProps = new HashMap<>();
cellProps.put(CellUtil.FILL_FOREGROUND_COLOR, colorIndex);
cellProps.put(CellUtil.FILL_PATTERN, FillPatternType.SOLID_FOREGROUND);
CellUtil.setCellStyleProperties(cell, cellProps);
}
Above, the applyPriceListDataCellStyle method is called after a Cell is created from a Row object. The cell instance is then passed into this method as an argument, along with my PriceListItem bean (which is the data I'm writing to each row in the Excel file).
The PriceListItem bean has a ChangeType property (enum) that dictates what color the cell should appear as in the final Excel file.
At runtime, I am calling this method on the cells of 5 different rows (so 5 different PriceListItems) of each ChangeType value, and I get output that looks like:
So:
The 1st row, which is a "NO_CHANGE" (which maps to IndexedColors.WHITE) works perfectly fine, as expected
The 2nd row, which is an "ADDITION" (which maps to IndexedColors.YELLOW) works perfectly fine, as expected
The 3rd row, which is a "DELETION" (which maps to my custom purple color) appears jet black instead -- wrong!
The 4th row, which is a "PRICE_ADJUSTMENT_INCREASE" (which maps to IndexedColors.RED) appears gray -- wrong!
The 5th row, which is a "PRICE_ADJUSTMENT_DECREASE" (which maps to IndexedColors.GREEN) appears a lighter shade of gray -- wrong!
Where am I going awry on setting the colors on the cells of these various rows?
The apache poi CellUtil only works using org.apache.poi.ss.*. It cannot work using a XSSFColor because org.apache.poi.ss.usermodel.CellStyle has no method to get/set fill foreground color from a XSSFColor. It only works using short color indexes from IndexedColors. Hence the black color, because in your code purple.getIndex() always returns 0. So if CellUtil shall be used, which is to recommend, then choose a color from IndexedColors instead of creating a custom color. There is IndexedColors.VIOLET for example.
But the other wrong cases are not reproducible for me. The following Minimal, Reproducible Example works for me as expected. It needs a price-list-template.xlsx having at least one worksheet.
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellUtil;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class PoiColors {
public static void main(String[] args) throws IOException {
List<PriceListItem> priceList = new ArrayList<>();
PriceListItem noChange = new PriceListItem();
noChange.modelNumber = "123";
noChange.price = BigDecimal.valueOf(1.99);
noChange.changeType = ChangeType.NO_CHANGE;
PriceListItem addition = new PriceListItem();
addition.modelNumber = "456";
addition.price = BigDecimal.valueOf(2.99);
addition.changeType = ChangeType.ADDITION;
PriceListItem deletion = new PriceListItem();
deletion.modelNumber = "789";
deletion.price = BigDecimal.valueOf(3.99);
deletion.changeType = ChangeType.DELETION;
PriceListItem increase = new PriceListItem();
increase.modelNumber = "234";
increase.price = BigDecimal.valueOf(4.99);
increase.changeType = ChangeType.PRICE_ADJUSTMENT_INCREASE;
PriceListItem decrease = new PriceListItem();
decrease.modelNumber = "345";
decrease.price = BigDecimal.valueOf(5.99);
decrease.changeType = ChangeType.PRICE_ADJUSTMENT_DECREASE;
priceList.add(noChange);
priceList.add(addition);
priceList.add(deletion);
priceList.add(increase);
priceList.add(decrease);
new PoiColors().exportPriceList(priceList, "acme.xlsx");
}
private void exportPriceList(
List<PriceListItem> priceList,
String targetAbsPath) throws IOException {
// set variables based on specified format
String templateName = "price-list-template.xlsx";
// load the template
InputStream inp = this.getClass().getClassLoader().getResource(templateName).openStream();
Workbook workbook = WorkbookFactory.create(inp);
Sheet sheet = workbook.getSheetAt(0);
workbook.setSheetName(workbook.getSheetIndex(sheet), "ACME");
// plug in the header/metadata info and format some headers so they get autosized properly
Row row2 = CellUtil.getRow(1, sheet);
Cell c2 = CellUtil.getCell(row2, 2);
c2.setCellValue("ACME");
// create the data rows and apply styling
// start at row #11 which is where data rows begin
int rowNum = 11;
// rip through the items and write them to the rows; apply styling as appropriate
for (PriceListItem priceListItem : priceList) {
Row nextRow = sheet.createRow(rowNum);
Cell changeType = nextRow.createCell(0);
changeType.setCellValue(priceListItem.changeType.name());
applyPriceListDataCellStyle(priceListItem, changeType);
Cell modelNumber = nextRow.createCell(1);
modelNumber.setCellValue(priceListItem.modelNumber);
applyPriceListDataCellStyle(priceListItem, modelNumber);
Cell price = nextRow.createCell(2);
price.setCellValue(priceListItem.price.doubleValue());
applyPriceListDataCellStyle(priceListItem, price);
rowNum++;
}
// resize the columns appropriately
for (int c = 0; c < 3; c++) {
sheet.autoSizeColumn(c);
}
// export to file system
FileOutputStream fos = new FileOutputStream(targetAbsPath);
workbook.write(fos);
fos.close();
inp.close();
workbook.close();
}
private void applyPriceListDataCellStyle(PriceListItem priceListItem, Cell cell) {
short colorIndex;
switch(priceListItem.changeType) {
case ADDITION:
colorIndex = IndexedColors.YELLOW.getIndex();
break;
case DELETION:
colorIndex = IndexedColors.VIOLET.getIndex();
break;
case PRICE_ADJUSTMENT_INCREASE:
colorIndex = IndexedColors.RED.getIndex();
break;
case PRICE_ADJUSTMENT_DECREASE:
colorIndex = IndexedColors.GREEN.getIndex();
break;
default:
// NO_CHANGE (leave unstyled)
colorIndex = IndexedColors.WHITE.getIndex();
break;
}
Map<String,Object> cellProps = new HashMap<>();
cellProps.put(CellUtil.FILL_FOREGROUND_COLOR, colorIndex);
cellProps.put(CellUtil.FILL_PATTERN, FillPatternType.SOLID_FOREGROUND);
CellUtil.setCellStyleProperties(cell, cellProps);
}
}
class PriceListItem {
public String modelNumber;
public BigDecimal price;
public ChangeType changeType;
}
enum ChangeType {
NO_CHANGE,
ADDITION,
DELETION,
PRICE_ADJUSTMENT_INCREASE,
PRICE_ADJUSTMENT_DECREASE
}
Result is acme.xlsx which looks like so:
Using IndexedColors the colors are set in Office Open XML /xl/styles.xml as follows:
...
<fill>
<patternFill patternType="solid">
<fgColor indexed="13"/>
<bgColor indexed="64"/>
</patternFill>
</fill>
...
The indexed colors are not given by RGB but are taken from the default color palette. If you have the suspicion that your spreadsheet calculation application uses a different default color palette than Excel, then you can test this using the following code:
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellUtil;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
public class TestIndexedColors {
public static void main(String[] args) throws Exception {
String templateName = "price-list-template.xlsx";
InputStream inp = TestIndexedColors.class.getClassLoader().getResource(templateName).openStream();
Workbook workbook = WorkbookFactory.create(inp);
Sheet sheet = workbook.getSheetAt(0);
Row row; Cell cell; int r = 11;
Map<String,Object> cellProps;
for (IndexedColors color : IndexedColors.values()) {
row = sheet.createRow(r++);
cell = row.createCell(0); cell.setCellValue(color.getIndex());
cell = row.createCell(1); cell.setCellValue(color.name());
cell = row.createCell(2);
cellProps = new HashMap<>();
cellProps.put(CellUtil.FILL_FOREGROUND_COLOR, color.getIndex());
cellProps.put(CellUtil.FILL_PATTERN, FillPatternType.SOLID_FOREGROUND);
CellUtil.setCellStyleProperties(cell, cellProps);
}
FileOutputStream out = new FileOutputStream("acme.xlsx");
workbook.write(out);
out.close();
workbook.close();
}
}
It needs a price-list-template.xlsx having at least one worksheet. The result acme.xlsx shows indexes, names and colors of all possible indexed colors using the current default color palette.

String cells data is not visible in excel editor when excel is created using SXSSFWorkbook and modified using XSSFWorkbook

Scenario:
1) A csv file is converted into excel file using SXSSFWorkbook.
2) If the data is again read from CSV file and written to the above generated excel file using XSSFWorkbook then the string data is not visible in libre office but data is visible if the excel file is opened in online excel viewer(some of the excel viewers are mentioning that the file is corrupt and data can be recoverable).
Cell creation Using SXSSFWorkbook:
Cell cell = row.createCell(1);
cell.setCellValue("Some Value");
Cell updation using XSSFWorkbook:
Cell cell = row.getCell(1);
cell.setCellValue("Some Value");
Observations:
1) When cell value is updated using XSSFCell, then the raw value of cell and string value of the cell are different.
2) If excel file is generated with SXSSFWorkbook and opened using XSSFWorkbook then internally maintained STCellType is STCellType.INLINE_STR and if excel file is generated using XSSFWorkbook then internally maintained STCellType is STCellType.S (STCellType is used in CTCell of XSSFCell).
Apache POI Version: 4.1.0
Please suggest solution.
The SXSSFWorkbook uses inline strings per default while XSSFWorkbook uses shared strings table per default. And XSSFCell.setCellValueImpl is incomplete for inline strings. It does:
...
if(_cell.getT() == STCellType.INLINE_STR) {
//set the 'pre-evaluated result
_cell.setV(str.getString());
}
...
So for inline strings it always sets v element containing the text. But inline strings also may have is element having t element containing the text, or even is element having different rich text runs. This is not considered using XSSFCell.
But SXSSFWorkbook can be constructed so it also uses shared strings table. See constructor SXSSFWorkbook(XSSFWorkbook workbook, int rowAccessWindowSize, boolean compressTmpFiles, boolean useSharedStringsTable). So if following constructor used:
SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(new XSSFWorkbook(), 2, true, true);
then no inline strings are used and later updating using XSSF will not be problematic.
If SXSSFWorkbook is not using shared strings table but inline strings, there is a problem when later updating cells using XSSF because of the incompleteness of XSSFCell in using inline strings. Possible workaround will be managing the inline strings updating with own code.
Example:
import java.io.FileOutputStream;
import java.io.FileInputStream;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.xssf.streaming.*;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellType;
public class SXSSFTest {
public static void main(String[] args) throws Exception {
// first create SXSSFTest.xlsx using SXSSF ============================================
String[][] data1 = new String[][]{
new String[]{"A1", "B1", "C1"},
new String[]{"A2", "B2", "C2"},
new String[]{"A3", "B3", "C3"},
new String[]{"A4", "B4", "C4"}
};
SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook();
//SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(new XSSFWorkbook(), 2, true, true);
SXSSFSheet sxssfSheet = sxssfWorkbook.createSheet();
int r = 0;
for (String[] rowValues : data1) {
SXSSFRow row = sxssfSheet.createRow(r++);
int c = 0;
for (String value : rowValues) {
SXSSFCell cell = row.createCell(c++);
cell.setCellValue(value);
}
}
FileOutputStream outputStream = new FileOutputStream("SXSSFTest.xlsx");
sxssfWorkbook.write(outputStream);
outputStream.close();
sxssfWorkbook.dispose();
sxssfWorkbook.close();
// now reread the SXSSFTest.xlsx and update it using XSSF =============================
String[][] data2 = new String[][]{
new String[]{"A2 New", "B2 New", "C2 New"},
new String[]{"A3 New", "B3 New", "C3 New"}
};
XSSFWorkbook xssfWorkbook = (XSSFWorkbook)WorkbookFactory.create(
new FileInputStream("SXSSFTest.xlsx"));
XSSFSheet xssfSheet = xssfWorkbook.getSheetAt(0);
r = 1;
for (String[] rowValues : data2) {
XSSFRow row = xssfSheet.getRow(r++); if (row == null) row = xssfSheet.createRow(r++);
int c = 0;
for (String value : rowValues) {
XSSFCell cell = row.getCell(c++);
if (cell != null) { // cell was already there
if (cell.getCTCell().getT() == STCellType.INLINE_STR) { // cell has inline string in it
if (cell.getCTCell().isSetIs()) { // inline string has is element
cell.getCTCell().getIs().setT(value); // set t element in is element
} else {
cell.getCTCell().setV(value); // set v element of inline string
}
} else {
cell.setCellValue(value); // set shared string cell value
}
} else {
cell = row.createCell(c++);
cell.setCellValue(value);
}
}
}
outputStream = new FileOutputStream("XSSFTest.xlsx");
xssfWorkbook.write(outputStream);
outputStream.close();
xssfWorkbook.close();
}
}
After that the SXSSFTest.xlsx looks like so in my LibreOffice Calc:
All cells have inline strings in it.
And the XSSFTest.xlsx looks like so:
There all inline strings are updated correctly now.
LibreOffice
Version: 6.0.7.3
Build ID: 1:6.0.7-0ubuntu0.18.04.5

Renaming headers of XSSFTable with Apache Poi leads to corrupt XLSX-file

I am trying to rename headers of an existing xlsx-file. The idea is to have an excel-file to export data from XML to excel and reimport the XML once some user has made adjustments.
At the moment we have created a "template" xlsx-sheet with Excel which already contains a sortable table (XSSFTable in poi) and a mapping to a XSD-source. Then we import it via POI, map XML data into it and save it. To adjust the sheet to the users we want to translate the headers/column-names of this existing table into different languages. It worked with POI 3.10-FINAL but since an upgrade to 4.0.1 it leads to a corrupt xlsx-file when opening.
I found this question on stackoverflow already
Excel file gets corrupted when i change the value of any cell in the header (Columns Title)
but it is not answered and pretty old. But I tried to figure out what the comments may were about and tried to flatten the existing XSSFTable, copy the filled data to a new sheet and put on a new XSSFTable to the data. Sadly this seems to be pretty complicated so I am back to correcting the broken header-cells.
I also tried to create the whole sheet with POI and step away from using that "template"-xslx, but I cannot figure out how to implement our XSD-Mapping (in Excel its Developer-Tools -> Source -> Add and then mapping the nodes to some cells in a dynamic table)
The code that worked until the upgrade of poi is basically this:
//Sheet is the current XSSFSheet
//header is a Map with the original header-name from the template mapped to a the new translated name
//headerrownumber is the row containing the tableheader to be translated
public static void translateHeaders(Sheet sheet,final Map<String,String> header,int headerrownumber) {
CellRangeAddress address = new CellRangeAddress(headerrownumber,headerrownumber,0,sheet.getRow(headerrownumber).getLastCellNum()); //Cellrange is the header-row
MyCellWalk cellWalk = new MyCellWalk (sheet,address);
cellWalk.traverse(new CellHandler() {
public void onCell(Cell cell, CellWalkContext ctx) {
String val = cell.getStringCellValue();
if (header.containsKey(val)) {
cell.setCellValue(header.get(val));
}
}
});
}
MyCellWalk is a org.apache.poi.ss.util.cellwalk.CellWalk which traverses the cell range from top left to the bottom right cell.
As far as I could figure out its not enough to simply change the flat value of the cell because xlsx keeps references to the cellname in some of their maps, but I cannot figure out how to grab them all and rename the header. Maybe there is also another approach in translating the headernames?
Well, the XSSFTable.updateHeaders should do the trick if apache poi would not fail doing it.
All the following is done using apache poi 4.0.1.
I have downloaded your dummy_template.xlsx and then tried changing the table column headers in the sheet. But even after calling XSSFTable.updateHeaders the column names in the XSSFTable has not changed. So I had a look into XSSFTable.java -> updateHeaders to determine why this not happens. There we find:
if (row != null && row.getCTRow().validate()) {
//do changing the column names
}
So the column names only will be changed if the corresponding row in the sheet is valid XML according to Office Open XML name spaces. But in later Excel versions (after 2007) additional name spaces were added. In this case the row's XML looks like:
<row r="4" spans="1:3" x14ac:dyDescent="0.25">
Note the additional x14ac:dyDescent attribute. That's why row.getCTRow().validate() returns false.
The following code gets your dummy_template.xlsx, renames the column headers in the sheet and then calls a disarmed version static void updateHeaders(XSSFTable table). After that the result.xlsx is valid for opening in Excel.
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.*;
import org.apache.poi.ss.util.cellwalk.*;
import org.apache.poi.xssf.usermodel.*;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
import java.io.*;
import java.util.*;
class ExcelRenameTableColumns {
static void translateHeaders(Sheet sheet, final Map<String,String> header, int headerrownumber) {
CellRangeAddress address = new CellRangeAddress(
headerrownumber, headerrownumber,
0, sheet.getRow(headerrownumber).getLastCellNum());
CellWalk cellWalk = new CellWalk (sheet, address);
cellWalk.traverse(new CellHandler() {
public void onCell(Cell cell, CellWalkContext ctx) {
String val = cell.getStringCellValue();
if (header.containsKey(val)) {
cell.setCellValue(header.get(val));
}
}
});
}
static void updateHeaders(XSSFTable table) {
XSSFSheet sheet = (XSSFSheet)table.getParent();
CellReference ref = table.getStartCellReference();
if (ref == null) return;
int headerRow = ref.getRow();
int firstHeaderColumn = ref.getCol();
XSSFRow row = sheet.getRow(headerRow);
DataFormatter formatter = new DataFormatter();
System.out.println(row.getCTRow().validate()); // false!
if (row != null /*&& row.getCTRow().validate()*/) {
int cellnum = firstHeaderColumn;
CTTableColumns ctTableColumns = table.getCTTable().getTableColumns();
if(ctTableColumns != null) {
for (CTTableColumn col : ctTableColumns.getTableColumnList()) {
XSSFCell cell = row.getCell(cellnum);
if (cell != null) {
col.setName(formatter.formatCellValue(cell));
}
cellnum++;
}
}
}
}
public static void main(String[] args) throws Exception {
String templatePath = "dummy_template.xlsx";
String outputPath = "result.xlsx";
FileInputStream inputStream = new FileInputStream(templatePath);
Workbook workbook = WorkbookFactory.create(inputStream);
Sheet sheet = workbook.getSheetAt(0);
Map<String, String> header = new HashMap<String, String>();
header.put("textone", "Spalte eins");
header.put("texttwo", "Spalte zwei");
header.put("textthree", "Spalte drei");
translateHeaders(sheet, header, 3);
XSSFTable table = ((XSSFSheet)sheet).getTables().get(0);
updateHeaders(table);
FileOutputStream outputStream = new FileOutputStream(outputPath);
workbook.write(outputStream);
outputStream.close();
workbook.close();
}
}
If I open the dummy_template.xlsx using Excel 2007 and then save as dummy_template2007.xlsx, the row's XML changes to
<row r="4" spans="1:3">
Now when using this dummy_template2007.xlsx no manually calling the XSSFTable.updateHeaders is necessary. The XSSFTable.writeTo which is called by XSSFTable.commit does this automatically.

JTable passing values to excel (Text formating)

I use the code that you can see below in order to strike through some cells in a jtable. Works great for me, and both in appearence and in print with JTable.print() method works excellent.
public void strikeThrough()
{
int rows=jTable.getRowCount();
destroiedDocs=new ArrayList<>();
for (int i = 0; i < rows; i++)
{
String test=String.valueOf(jTable.getValueAt(i,5));
if (test.equals("K"))
{
for (int j = 1; j < 5; j++)
{
String tostrike= String.valueOf(jTable.getValueAt(i, j));
String striked=("<html><strike>".concat(tostrike).concat("</strike> </html>"));
jTable.setValueAt(striked, i, j);
destroiedDocs.add(i);
}
}
}
}
The problem is that when I export the resaults to excel with the jxl class I got the value in these strike through cells with the appearence
<html><strike>some text</strike></html>
instead of some text in strikethrough.
Any recomandations on how to solve this formating problem?
I pass the cells in the excel cell by cell from the jtable with loops.
Thank you!
The JAVA code:
String striked=("<html><strike>".concat(tostrike).concat("</strike> </html>"));
jTable.setValueAt(striked, i, j);
Will work only for JAVA UI. After exporting data to excel it will show original text.
You need to perform following steps:
1. Before exporting remove <html><strike> and </strike></html>. Keep original text.
2. Use following code to strikethrough cell.
Run the following code using jxl-2.6.10.jar
import java.io.File;
import jxl.Workbook;
import jxl.write.Label;
import jxl.write.WritableCell;
import jxl.write.WritableCellFormat;
import jxl.write.WritableFont;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
public class ExcelCreate {
public static void main(String[] args) {
try {
WritableWorkbook workbook =
Workbook.createWorkbook(new File("output.xls"));
WritableSheet sheet = workbook.createSheet("Page1", 0);
String Label[] = new String[4];
Label[0] = "Emp ID";
Label[1] = "Name";
Label[2] = "Department";
Label[3] = "Designation";
WritableCellFormat cellFormat = new WritableCellFormat();
WritableFont font = new WritableFont(WritableFont.ARIAL);
font.setStruckout(true);
cellFormat.setFont(font);
for (int i = 0; i < Label.length; i++) {
Label label = new Label(i, 0, Label[i]);
sheet.addCell(label);
WritableCell cell = sheet.getWritableCell(i, 0);
cell.setCellFormat(cellFormat);
}
workbook.write();
workbook.close();
} catch (Exception e) {
/* Write your logic to handle exception.
*/
}
}
}
I think before export each cell to the Excel you'll have to find and replace or remove the tags like
<html>
and
<strike>
with appropriate functions to add the required formatting..
Which API are you using to export it to Excel Format??
I think it'll be Specific the one that you're using to export to Excel.

Categories

Resources