From 2ce00a5a782823a01b5d8bab1d71cb36690bfbbc Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Wed, 7 Jun 2017 12:39:41 +0000 Subject: [PATCH] XSSFTable should format numeric/date cells when used as Column Header names as Excel does, see https://stackoverflow.com/questions/44407111/apache-poi-cant-format-filled-cells-as-numeric git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1797914 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/poi/xssf/usermodel/XSSFTable.java | 24 +++++- .../poi/xssf/usermodel/TestXSSFTable.java | 78 ++++++++++++++++++ .../TablesWithDifferentHeaders.xlsx | Bin 0 -> 11359 bytes 3 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 test-data/spreadsheet/TablesWithDifferentHeaders.xlsx diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTable.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTable.java index ad9e09bef..ef8ace666 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTable.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTable.java @@ -31,8 +31,10 @@ import java.util.Locale; import org.apache.poi.POIXMLDocumentPart; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.DataFormatter; import org.apache.poi.ss.usermodel.Table; import org.apache.poi.ss.usermodel.TableStyleInfo; +import org.apache.poi.ss.util.AreaReference; import org.apache.poi.ss.util.CellReference; import org.apache.poi.util.Internal; import org.apache.poi.util.StringUtil; @@ -311,7 +313,20 @@ public class XSSFTable extends POIXMLDocumentPart implements Table { return getNumberOfMappedColumns(); } - + /** + * @return The reference for the cells of the table + * (see Open Office XML Part 4: chapter 3.5.1.2, attribute ref) + * + * Does not track updates to underlying changes to CTTable + * To synchronize with changes to the underlying CTTable, + * call {@link #updateReferences()}. + */ + public AreaReference getReferences() { + return new AreaReference( + getStartCellReference(), + getEndCellReference() + ); + } /** * @return The reference for the cell in the top-left part of the table @@ -401,6 +416,10 @@ public class XSSFTable extends POIXMLDocumentPart implements Table { * If calling both {@link #updateReferences()} and * {@link #updateHeaders()}, {@link #updateReferences()} * should be called first. + * + * Note that a Table must have a header. To reproduce + * the equivalent of inserting a table in Excel without Headers, + * manually add cells with values of "Column1", "Column2" etc first. */ public void updateHeaders() { XSSFSheet sheet = (XSSFSheet)getParent(); @@ -410,13 +429,14 @@ public class XSSFTable extends POIXMLDocumentPart implements Table { int headerRow = ref.getRow(); int firstHeaderColumn = ref.getCol(); XSSFRow row = sheet.getRow(headerRow); + DataFormatter formatter = new DataFormatter(); if (row != null && row.getCTRow().validate()) { int cellnum = firstHeaderColumn; for (CTTableColumn col : getCTTable().getTableColumns().getTableColumnArray()) { XSSFCell cell = row.getCell(cellnum); if (cell != null) { - col.setName(cell.getStringCellValue()); + col.setName(formatter.formatCellValue(cell)); } cellnum++; } diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFTable.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFTable.java index 69b412a51..e9e7f3a88 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFTable.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFTable.java @@ -38,6 +38,7 @@ import org.apache.poi.xssf.streaming.SXSSFWorkbook; import org.junit.Test; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTable; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumns; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableStyleInfo; public final class TestXSSFTable { @@ -287,4 +288,81 @@ public final class TestXSSFTable { table.updateReferences(); assertEquals(11, table.getRowCount()); } + + @Test + public void testDifferentHeaderTypes() throws IOException { + XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("TablesWithDifferentHeaders.xlsx"); + assertEquals(3, wb.getNumberOfSheets()); + XSSFSheet s; + XSSFTable t; + + // TODO Nicer column fetching + + s = wb.getSheet("IntHeaders"); + assertEquals(1, s.getTables().size()); + t = s.getTables().get(0); + assertEquals("A1:B2", t.getReferences().formatAsString()); + assertEquals("12", t.getCTTable().getTableColumns().getTableColumnArray(0).getName()); + assertEquals("34", t.getCTTable().getTableColumns().getTableColumnArray(1).getName()); + + s = wb.getSheet("FloatHeaders"); + assertEquals(1, s.getTables().size()); + t = s.getTables().get(0); + assertEquals("A1:B2", t.getReferences().formatAsString()); + assertEquals("12.34", t.getCTTable().getTableColumns().getTableColumnArray(0).getName()); + assertEquals("34.56", t.getCTTable().getTableColumns().getTableColumnArray(1).getName()); + + s = wb.getSheet("NoExplicitHeaders"); + assertEquals(1, s.getTables().size()); + t = s.getTables().get(0); + assertEquals("A1:B3", t.getReferences().formatAsString()); + assertEquals("Column1", t.getCTTable().getTableColumns().getTableColumnArray(0).getName()); + assertEquals("Column2", t.getCTTable().getTableColumns().getTableColumnArray(1).getName()); + } + + /** + * See https://stackoverflow.com/questions/44407111/apache-poi-cant-format-filled-cells-as-numeric + */ + @Test + public void testNumericCellsInTable() throws IOException { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet s = wb.createSheet(); + + //Setting up the CTTable + XSSFTable t = s.createTable(); + CTTable ctt = t.getCTTable(); + ctt.setId(1); + ctt.setName("CT Table Test"); + ctt.setRef("A1:B2"); + CTTableColumns cttcs = ctt.addNewTableColumns(); + CTTableColumn cttc1 = cttcs.addNewTableColumn(); + cttc1.setId(1); + CTTableColumn cttc2 = cttcs.addNewTableColumn(); + cttc2.setId(2); + + //Creating the cells + Cell c1 = s.createRow(0).createCell(0); + XSSFCell c2 = s.getRow(0).createCell(1); + XSSFCell c3 = s.createRow(1).createCell(0); + XSSFCell c4 = s.getRow(1).createCell(1); + + // Inserting values; some numeric strings, some alphabetical strings + c1.setCellValue(12); + c2.setCellValue(34); + c3.setCellValue("AB"); + c4.setCellValue("CD"); + + // Save and re-load + wb = XSSFTestDataSamples.writeOutAndReadBack(wb); + s = wb.getSheetAt(0); + + // Check + assertEquals(1, s.getTables().size()); + t = s.getTables().get(0); + assertEquals("A1", t.getStartCellReference().formatAsString()); + assertEquals("B2", t.getEndCellReference().formatAsString()); + + // Done + wb.close(); + } } diff --git a/test-data/spreadsheet/TablesWithDifferentHeaders.xlsx b/test-data/spreadsheet/TablesWithDifferentHeaders.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..c9bb110adca01481083f965e6064d27657fe62e6 GIT binary patch literal 11359 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 literal 0 HcmV?d00001